[libc-commits] [libc] [libc][stdfix] Implement `countlsfx` functions (PR #114318)

via libc-commits libc-commits at lists.llvm.org
Wed Oct 30 20:56:22 PDT 2024


https://github.com/duncpro updated https://github.com/llvm/llvm-project/pull/114318

>From 1c012af61f7b2110d047e311203928c45af46131 Mon Sep 17 00:00:00 2001
From: Duncan <duncpro at icloud.com>
Date: Tue, 29 Oct 2024 22:33:41 -0400
Subject: [PATCH] [libc] [stdfix] implement `countlsfx` functions

---
 libc/config/baremetal/arm/entrypoints.txt     | 12 +++
 libc/config/baremetal/riscv/entrypoints.txt   | 12 +++
 libc/config/linux/riscv/entrypoints.txt       | 12 +++
 libc/config/linux/x86_64/entrypoints.txt      | 12 +++
 libc/newhdrgen/yaml/stdfix.yaml               | 84 +++++++++++++++++++
 libc/spec/stdc_ext.td                         | 17 ++++
 libc/src/__support/fixed_point/CMakeLists.txt |  1 +
 libc/src/__support/fixed_point/fx_bits.h      | 39 ++++++++-
 libc/src/__support/fixed_point/fx_rep.h       | 12 +++
 libc/src/stdfix/CMakeLists.txt                | 14 ++++
 libc/src/stdfix/countlshk.cpp                 | 20 +++++
 libc/src/stdfix/countlshk.h                   | 21 +++++
 libc/src/stdfix/countlshr.cpp                 | 20 +++++
 libc/src/stdfix/countlshr.h                   | 21 +++++
 libc/src/stdfix/countlsk.cpp                  | 18 ++++
 libc/src/stdfix/countlsk.h                    | 21 +++++
 libc/src/stdfix/countlslk.cpp                 | 20 +++++
 libc/src/stdfix/countlslk.h                   | 21 +++++
 libc/src/stdfix/countlslr.cpp                 | 20 +++++
 libc/src/stdfix/countlslr.h                   | 21 +++++
 libc/src/stdfix/countlsr.cpp                  | 18 ++++
 libc/src/stdfix/countlsr.h                    | 21 +++++
 libc/src/stdfix/countlsuhk.cpp                | 20 +++++
 libc/src/stdfix/countlsuhk.h                  | 21 +++++
 libc/src/stdfix/countlsuhr.cpp                | 20 +++++
 libc/src/stdfix/countlsuhr.h                  | 21 +++++
 libc/src/stdfix/countlsuk.cpp                 | 20 +++++
 libc/src/stdfix/countlsuk.h                   | 21 +++++
 libc/src/stdfix/countlsulk.cpp                | 20 +++++
 libc/src/stdfix/countlsulk.h                  | 21 +++++
 libc/src/stdfix/countlsulr.cpp                | 20 +++++
 libc/src/stdfix/countlsulr.h                  | 21 +++++
 libc/src/stdfix/countlsur.cpp                 | 20 +++++
 libc/src/stdfix/countlsur.h                   | 21 +++++
 libc/test/src/stdfix/CMakeLists.txt           | 17 ++++
 libc/test/src/stdfix/CountlsTest.h            | 48 +++++++++++
 libc/test/src/stdfix/countlshk_test.cpp       | 13 +++
 libc/test/src/stdfix/countlshr_test.cpp       | 13 +++
 libc/test/src/stdfix/countlsk_test.cpp        | 13 +++
 libc/test/src/stdfix/countlslk_test.cpp       | 13 +++
 libc/test/src/stdfix/countlslr_test.cpp       | 13 +++
 libc/test/src/stdfix/countlsr_test.cpp        | 13 +++
 libc/test/src/stdfix/countlsuhk_test.cpp      | 13 +++
 libc/test/src/stdfix/countlsuhr_test.cpp      | 13 +++
 libc/test/src/stdfix/countlsuk_test.cpp       | 13 +++
 libc/test/src/stdfix/countlsulk_test.cpp      | 13 +++
 libc/test/src/stdfix/countlsulr_test.cpp      | 13 +++
 libc/test/src/stdfix/countlsur_test.cpp       | 13 +++
 48 files changed, 923 insertions(+), 1 deletion(-)
 create mode 100644 libc/src/stdfix/countlshk.cpp
 create mode 100644 libc/src/stdfix/countlshk.h
 create mode 100644 libc/src/stdfix/countlshr.cpp
 create mode 100644 libc/src/stdfix/countlshr.h
 create mode 100644 libc/src/stdfix/countlsk.cpp
 create mode 100644 libc/src/stdfix/countlsk.h
 create mode 100644 libc/src/stdfix/countlslk.cpp
 create mode 100644 libc/src/stdfix/countlslk.h
 create mode 100644 libc/src/stdfix/countlslr.cpp
 create mode 100644 libc/src/stdfix/countlslr.h
 create mode 100644 libc/src/stdfix/countlsr.cpp
 create mode 100644 libc/src/stdfix/countlsr.h
 create mode 100644 libc/src/stdfix/countlsuhk.cpp
 create mode 100644 libc/src/stdfix/countlsuhk.h
 create mode 100644 libc/src/stdfix/countlsuhr.cpp
 create mode 100644 libc/src/stdfix/countlsuhr.h
 create mode 100644 libc/src/stdfix/countlsuk.cpp
 create mode 100644 libc/src/stdfix/countlsuk.h
 create mode 100644 libc/src/stdfix/countlsulk.cpp
 create mode 100644 libc/src/stdfix/countlsulk.h
 create mode 100644 libc/src/stdfix/countlsulr.cpp
 create mode 100644 libc/src/stdfix/countlsulr.h
 create mode 100644 libc/src/stdfix/countlsur.cpp
 create mode 100644 libc/src/stdfix/countlsur.h
 create mode 100644 libc/test/src/stdfix/CountlsTest.h
 create mode 100644 libc/test/src/stdfix/countlshk_test.cpp
 create mode 100644 libc/test/src/stdfix/countlshr_test.cpp
 create mode 100644 libc/test/src/stdfix/countlsk_test.cpp
 create mode 100644 libc/test/src/stdfix/countlslk_test.cpp
 create mode 100644 libc/test/src/stdfix/countlslr_test.cpp
 create mode 100644 libc/test/src/stdfix/countlsr_test.cpp
 create mode 100644 libc/test/src/stdfix/countlsuhk_test.cpp
 create mode 100644 libc/test/src/stdfix/countlsuhr_test.cpp
 create mode 100644 libc/test/src/stdfix/countlsuk_test.cpp
 create mode 100644 libc/test/src/stdfix/countlsulk_test.cpp
 create mode 100644 libc/test/src/stdfix/countlsulr_test.cpp
 create mode 100644 libc/test/src/stdfix/countlsur_test.cpp

diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt
index 68030f7f1775b5..55af5413259a30 100644
--- a/libc/config/baremetal/arm/entrypoints.txt
+++ b/libc/config/baremetal/arm/entrypoints.txt
@@ -427,6 +427,18 @@ set(TARGET_LIBM_ENTRYPOINTS
 if(LIBC_COMPILER_HAS_FIXED_POINT)
   list(APPEND TARGET_LIBM_ENTRYPOINTS
     # stdfix.h _Fract and _Accum entrypoints
+    libc.src.stdfix.countlshk
+    libc.src.stdfix.countlshr
+    libc.src.stdfix.countlsk
+    libc.src.stdfix.countlslk
+    libc.src.stdfix.countlslr
+    libc.src.stdfix.countlsr
+    libc.src.stdfix.countlsuhk
+    libc.src.stdfix.countlsuhr
+    libc.src.stdfix.countlsuk
+    libc.src.stdfix.countlsulk
+    libc.src.stdfix.countlsulr
+    libc.src.stdfix.countlsur
     libc.src.stdfix.abshk
     libc.src.stdfix.abshr
     libc.src.stdfix.absk
diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt
index 5894b591072ef0..baa4b27b98aee0 100644
--- a/libc/config/baremetal/riscv/entrypoints.txt
+++ b/libc/config/baremetal/riscv/entrypoints.txt
@@ -422,6 +422,18 @@ set(TARGET_LIBM_ENTRYPOINTS
 if(LIBC_COMPILER_HAS_FIXED_POINT)
   list(APPEND TARGET_LIBM_ENTRYPOINTS
     # stdfix.h _Fract and _Accum entrypoints
+    libc.src.stdfix.countlshk
+    libc.src.stdfix.countlshr
+    libc.src.stdfix.countlsk
+    libc.src.stdfix.countlslk
+    libc.src.stdfix.countlslr
+    libc.src.stdfix.countlsr
+    libc.src.stdfix.countlsuhk
+    libc.src.stdfix.countlsuhr
+    libc.src.stdfix.countlsuk
+    libc.src.stdfix.countlsulk
+    libc.src.stdfix.countlsulr
+    libc.src.stdfix.countlsur
     libc.src.stdfix.abshk
     libc.src.stdfix.abshr
     libc.src.stdfix.absk
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 5c09edf7cfb266..cbbe9d226e05f9 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -677,6 +677,18 @@ endif()
 if(LIBC_COMPILER_HAS_FIXED_POINT)
   list(APPEND TARGET_LIBM_ENTRYPOINTS
     # stdfix.h _Fract and _Accum entrypoints
+    libc.src.stdfix.countlshk
+    libc.src.stdfix.countlshr
+    libc.src.stdfix.countlsk
+    libc.src.stdfix.countlslk
+    libc.src.stdfix.countlslr
+    libc.src.stdfix.countlsr
+    libc.src.stdfix.countlsuhk
+    libc.src.stdfix.countlsuhr
+    libc.src.stdfix.countlsuk
+    libc.src.stdfix.countlsulk
+    libc.src.stdfix.countlsulr
+    libc.src.stdfix.countlsur
     libc.src.stdfix.abshk
     libc.src.stdfix.abshr
     libc.src.stdfix.absk
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index a2fb97d04584d5..c0bf1ce50328e5 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -780,6 +780,18 @@ endif()
 if(LIBC_COMPILER_HAS_FIXED_POINT)
   list(APPEND TARGET_LIBM_ENTRYPOINTS
     # stdfix.h _Fract and _Accum entrypoints
+    libc.src.stdfix.countlshk
+    libc.src.stdfix.countlshr
+    libc.src.stdfix.countlsk
+    libc.src.stdfix.countlslk
+    libc.src.stdfix.countlslr
+    libc.src.stdfix.countlsr
+    libc.src.stdfix.countlsuhk
+    libc.src.stdfix.countlsuhr
+    libc.src.stdfix.countlsuk
+    libc.src.stdfix.countlsulk
+    libc.src.stdfix.countlsulr
+    libc.src.stdfix.countlsur
     libc.src.stdfix.abshk
     libc.src.stdfix.abshr
     libc.src.stdfix.absk
diff --git a/libc/newhdrgen/yaml/stdfix.yaml b/libc/newhdrgen/yaml/stdfix.yaml
index ca6658939e2278..abf2e4761005de 100644
--- a/libc/newhdrgen/yaml/stdfix.yaml
+++ b/libc/newhdrgen/yaml/stdfix.yaml
@@ -4,6 +4,90 @@ types: []
 enums: []
 objects: []
 functions:
+  - name: countlshk
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: short accum
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlshr
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: short fract
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlsk
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: accum
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlslk
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: long accum
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlslr
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: long fract
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlsr
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: fract
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlsuhk
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: unsigned short accum
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlsuhr
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: unsigned short fract
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlsuk
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: unsigned accum
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlsulk
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: unsigned long accum
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlsulr
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: unsigned long fract
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
+  - name: countlsur
+    standards:
+      - stdc_ext
+    return_type: int
+    arguments:
+      - type: unsigned fract
+    guard: LIBC_COMPILER_HAS_FIXED_POINT
   - name: abshk
     standards:
       - stdc_ext
diff --git a/libc/spec/stdc_ext.td b/libc/spec/stdc_ext.td
index 6620142146c471..26f2d526168ce7 100644
--- a/libc/spec/stdc_ext.td
+++ b/libc/spec/stdc_ext.td
@@ -24,6 +24,23 @@ def StdcExt : StandardSpec<"stdc_ext"> {
       [],  // types
       [],  // enums
       [    // functions
+
+          GuardedFunctionSpec<"countlshr", RetValSpec<ShortFractType>, [ArgSpec<ShortFractType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+          GuardedFunctionSpec<"countlsr", RetValSpec<FractType>, [ArgSpec<FractType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+          GuardedFunctionSpec<"countlslr", RetValSpec<LongFractType>, [ArgSpec<LongFractType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+
+          GuardedFunctionSpec<"countlshk", RetValSpec<ShortAccumType>, [ArgSpec<ShortAccumType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+          GuardedFunctionSpec<"countlsk", RetValSpec<AccumType>, [ArgSpec<AccumType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+          GuardedFunctionSpec<"countlslk", RetValSpec<LongAccumType>, [ArgSpec<LongAccumType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+
+          GuardedFunctionSpec<"countlsuhr", RetValSpec<UnsignedShortFractType>, [ArgSpec<UnsignedShortFractType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+          GuardedFunctionSpec<"countlsur", RetValSpec<UnsignedFractType>, [ArgSpec<UnsignedFractType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+          GuardedFunctionSpec<"countlsulr", RetValSpec<UnsignedLongFractType>, [ArgSpec<UnsignedLongFractType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+
+          GuardedFunctionSpec<"countlsuhk", RetValSpec<UnsignedShortAccumType>, [ArgSpec<UnsignedShortAccumType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+          GuardedFunctionSpec<"countlsuk", RetValSpec<UnsignedAccumType>, [ArgSpec<UnsignedAccumType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+          GuardedFunctionSpec<"countlsulk", RetValSpec<UnsignedLongAccumType>, [ArgSpec<UnsignedLongAccumType>, ArgSpec<IntType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
+  
           GuardedFunctionSpec<"abshr", RetValSpec<ShortFractType>, [ArgSpec<ShortFractType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
           GuardedFunctionSpec<"absr", RetValSpec<FractType>, [ArgSpec<FractType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
           GuardedFunctionSpec<"abslr", RetValSpec<LongFractType>, [ArgSpec<LongFractType>], "LIBC_COMPILER_HAS_FIXED_POINT">,
diff --git a/libc/src/__support/fixed_point/CMakeLists.txt b/libc/src/__support/fixed_point/CMakeLists.txt
index 3b744081765e4f..2531285d5c9cb2 100644
--- a/libc/src/__support/fixed_point/CMakeLists.txt
+++ b/libc/src/__support/fixed_point/CMakeLists.txt
@@ -20,6 +20,7 @@ add_header_library(
     libc.src.__support.CPP.type_traits
     libc.src.__support.CPP.bit
     libc.src.__support.math_extras
+    libc.src.__support.CPP.limits
 )
 
 add_header_library(
diff --git a/libc/src/__support/fixed_point/fx_bits.h b/libc/src/__support/fixed_point/fx_bits.h
index 0a4c21fb6a14f7..6d768ddc747d28 100644
--- a/libc/src/__support/fixed_point/fx_bits.h
+++ b/libc/src/__support/fixed_point/fx_bits.h
@@ -11,8 +11,9 @@
 
 #include "include/llvm-libc-macros/stdfix-macros.h"
 #include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/limits.h" // numeric_limits
 #include "src/__support/CPP/type_traits.h"
-#include "src/__support/macros/attributes.h"   // LIBC_INLINE
+#include "src/__support/macros/attributes.h" // LIBC_INLINE
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
 #include "src/__support/math_extras.h"
@@ -66,6 +67,23 @@ template <typename T> struct FXBits {
     }
   }
 
+  // Clause 6.2.6.3 of ISO/IEC TR 18037 defines the value bits of a fixed-point
+  // type to include the integral and fraction bits but not padding nor sign
+  // bits.
+  //
+  // This function returns the value bits, right-aligned, as an unsigned integer
+  // type which is at least large enough to hold them all.
+  //
+  // Note the integral and fraction bits are contiguous. The rightmost bits in
+  // the returned value are the fraciton bits, then immediately left of those
+  // are the integral bits.
+  //
+  // Any left-padding in the return value is guaranteed to be zero.
+  LIBC_INLINE constexpr StorageType get_value_bits() {
+    constexpr StorageType VALUE_MASK = INTEGRAL_MASK | FRACTION_MASK;
+    return (value & VALUE_MASK) >> FRACTION_OFFSET;
+  }
+
   LIBC_INLINE constexpr StorageType get_fraction() {
     return (value & FRACTION_MASK) >> FRACTION_OFFSET;
   }
@@ -142,6 +160,25 @@ template <typename T> LIBC_INLINE constexpr T abs(T x) {
   }
 }
 
+template <typename T>
+LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, int>
+countls(T x) {
+  using FXRep = FXRep<T>;
+  using BitType = typename FXRep::StorageType;
+  constexpr int CONTAIN_LEN = cpp::numeric_limits<BitType>::digits;
+  constexpr int PADDING_LEN = CONTAIN_LEN - FXRep::VALUE_LEN;
+
+  if constexpr (FXRep::SIGN_LEN != 0) {
+    if (x < 0) {
+      x = -(x + FXRep::EPS());
+    }
+  }
+
+  FXBits<T> fxbits(x);
+  BitType value_bits = fxbits.get_value_bits();
+  return cpp::countl_zero(value_bits) - PADDING_LEN;
+}
+
 // Round-to-nearest, tie-to-(+Inf)
 template <typename T> LIBC_INLINE constexpr T round(T x, int n) {
   using FXRep = FXRep<T>;
diff --git a/libc/src/__support/fixed_point/fx_rep.h b/libc/src/__support/fixed_point/fx_rep.h
index 186938947694e5..f1321e6a629ee5 100644
--- a/libc/src/__support/fixed_point/fx_rep.h
+++ b/libc/src/__support/fixed_point/fx_rep.h
@@ -45,6 +45,7 @@ template <> struct FXRep<short fract> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SFRACT_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return SFRACT_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return SFRACT_MAX; }
@@ -65,6 +66,7 @@ template <> struct FXRep<unsigned short fract> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = USFRACT_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return USFRACT_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return USFRACT_MAX; }
@@ -85,6 +87,7 @@ template <> struct FXRep<fract> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = FRACT_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return FRACT_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return FRACT_MAX; }
@@ -105,6 +108,7 @@ template <> struct FXRep<unsigned fract> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = UFRACT_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return UFRACT_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return UFRACT_MAX; }
@@ -125,6 +129,7 @@ template <> struct FXRep<long fract> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = LFRACT_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return LFRACT_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return LFRACT_MAX; }
@@ -145,6 +150,7 @@ template <> struct FXRep<unsigned long fract> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = ULFRACT_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return ULFRACT_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return ULFRACT_MAX; }
@@ -165,6 +171,7 @@ template <> struct FXRep<short accum> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = SACCUM_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return SACCUM_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return SACCUM_MAX; }
@@ -185,6 +192,7 @@ template <> struct FXRep<unsigned short accum> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = USACCUM_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return USACCUM_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return USACCUM_MAX; }
@@ -205,6 +213,7 @@ template <> struct FXRep<accum> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = ACCUM_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return ACCUM_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return ACCUM_MAX; }
@@ -225,6 +234,7 @@ template <> struct FXRep<unsigned accum> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = UACCUM_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return UACCUM_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return UACCUM_MAX; }
@@ -245,6 +255,7 @@ template <> struct FXRep<long accum> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = LACCUM_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return LACCUM_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return LACCUM_MAX; }
@@ -265,6 +276,7 @@ template <> struct FXRep<unsigned long accum> {
   LIBC_INLINE_VAR static constexpr int FRACTION_LEN = ULACCUM_FBIT;
   LIBC_INLINE_VAR static constexpr int TOTAL_LEN =
       SIGN_LEN + INTEGRAL_LEN + FRACTION_LEN;
+  LIBC_INLINE_VAR static constexpr int VALUE_LEN = INTEGRAL_LEN + FRACTION_LEN;
 
   LIBC_INLINE static constexpr Type MIN() { return ULACCUM_MIN; }
   LIBC_INLINE static constexpr Type MAX() { return ULACCUM_MAX; }
diff --git a/libc/src/stdfix/CMakeLists.txt b/libc/src/stdfix/CMakeLists.txt
index 10d76ae31349f9..69e0117effb50d 100644
--- a/libc/src/stdfix/CMakeLists.txt
+++ b/libc/src/stdfix/CMakeLists.txt
@@ -2,6 +2,20 @@ if(NOT LIBC_COMPILER_HAS_FIXED_POINT)
   return()
 endif()
 
+foreach(suffix IN ITEMS hr r lr hk k lk uhr ur ulr uhk uk ulk)
+  add_entrypoint_object(
+    countls${suffix}
+    HDRS
+      countls${suffix}.h
+    SRCS
+      countls${suffix}.cpp
+    COMPILE_OPTIONS
+      -O3
+    DEPENDS
+      libc.src.__support.fixed_point.fx_bits
+  )
+endforeach()
+
 foreach(suffix IN ITEMS hr r lr hk k lk)
   add_entrypoint_object(
     abs${suffix}
diff --git a/libc/src/stdfix/countlshk.cpp b/libc/src/stdfix/countlshk.cpp
new file mode 100644
index 00000000000000..d65d96312c0768
--- /dev/null
+++ b/libc/src/stdfix/countlshk.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlshk.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlshk, (short accum x)) {
+  return fixed_point::countls(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlshk.h b/libc/src/stdfix/countlshk.h
new file mode 100644
index 00000000000000..279fb985552347
--- /dev/null
+++ b/libc/src/stdfix/countlshk.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSHK_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSHK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlshk(short accum x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSHK_H
diff --git a/libc/src/stdfix/countlshr.cpp b/libc/src/stdfix/countlshr.cpp
new file mode 100644
index 00000000000000..ed3fd23e0cdf8f
--- /dev/null
+++ b/libc/src/stdfix/countlshr.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlshr.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlshr, (short fract x)) {
+  return fixed_point::countls(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlshr.h b/libc/src/stdfix/countlshr.h
new file mode 100644
index 00000000000000..a2307ee0656ced
--- /dev/null
+++ b/libc/src/stdfix/countlshr.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSHR_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSHR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlshr(short fract x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSHR_H
diff --git a/libc/src/stdfix/countlsk.cpp b/libc/src/stdfix/countlsk.cpp
new file mode 100644
index 00000000000000..470f2e28539c16
--- /dev/null
+++ b/libc/src/stdfix/countlsk.cpp
@@ -0,0 +1,18 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlsk.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlsk, (accum x)) { return fixed_point::countls(x); }
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlsk.h b/libc/src/stdfix/countlsk.h
new file mode 100644
index 00000000000000..fff9bed7499c5b
--- /dev/null
+++ b/libc/src/stdfix/countlsk.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSK_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlsk(accum x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSK_H
diff --git a/libc/src/stdfix/countlslk.cpp b/libc/src/stdfix/countlslk.cpp
new file mode 100644
index 00000000000000..b3d314368e7e23
--- /dev/null
+++ b/libc/src/stdfix/countlslk.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlslk.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlslk, (long accum x)) {
+  return fixed_point::countls(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlslk.h b/libc/src/stdfix/countlslk.h
new file mode 100644
index 00000000000000..0d20779ef18090
--- /dev/null
+++ b/libc/src/stdfix/countlslk.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSLK_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSLK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlslk(long accum x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSLK_H
diff --git a/libc/src/stdfix/countlslr.cpp b/libc/src/stdfix/countlslr.cpp
new file mode 100644
index 00000000000000..782a50b5ace6b1
--- /dev/null
+++ b/libc/src/stdfix/countlslr.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlslr.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlslr, (long fract x)) {
+  return fixed_point::countls(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlslr.h b/libc/src/stdfix/countlslr.h
new file mode 100644
index 00000000000000..28d639513215d0
--- /dev/null
+++ b/libc/src/stdfix/countlslr.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSLR_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSLR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlslr(long fract x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSLR_H
diff --git a/libc/src/stdfix/countlsr.cpp b/libc/src/stdfix/countlsr.cpp
new file mode 100644
index 00000000000000..64a2f109926284
--- /dev/null
+++ b/libc/src/stdfix/countlsr.cpp
@@ -0,0 +1,18 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlsr.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlsr, (fract x)) { return fixed_point::countls(x); }
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlsr.h b/libc/src/stdfix/countlsr.h
new file mode 100644
index 00000000000000..244ff54fabe38d
--- /dev/null
+++ b/libc/src/stdfix/countlsr.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSR_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlsr(fract x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSR_H
diff --git a/libc/src/stdfix/countlsuhk.cpp b/libc/src/stdfix/countlsuhk.cpp
new file mode 100644
index 00000000000000..53323e71410d50
--- /dev/null
+++ b/libc/src/stdfix/countlsuhk.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlsuhk.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlsuhk, (unsigned short accum x)) {
+  return fixed_point::countls(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlsuhk.h b/libc/src/stdfix/countlsuhk.h
new file mode 100644
index 00000000000000..502d64a6ab91b0
--- /dev/null
+++ b/libc/src/stdfix/countlsuhk.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSUHK_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSUHK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlsuhk(unsigned short accum x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSUHK_H
diff --git a/libc/src/stdfix/countlsuhr.cpp b/libc/src/stdfix/countlsuhr.cpp
new file mode 100644
index 00000000000000..7a5a9156a31ff7
--- /dev/null
+++ b/libc/src/stdfix/countlsuhr.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlsuhr.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlsuhr, (unsigned short fract x)) {
+  return fixed_point::countls(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlsuhr.h b/libc/src/stdfix/countlsuhr.h
new file mode 100644
index 00000000000000..5e31f18344a766
--- /dev/null
+++ b/libc/src/stdfix/countlsuhr.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSUHR_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSUHR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlsuhr(unsigned short fract x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSUHR_H
diff --git a/libc/src/stdfix/countlsuk.cpp b/libc/src/stdfix/countlsuk.cpp
new file mode 100644
index 00000000000000..a47da60c80ddc3
--- /dev/null
+++ b/libc/src/stdfix/countlsuk.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlsuk.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlsuk, (unsigned accum x)) {
+  return fixed_point::countls(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlsuk.h b/libc/src/stdfix/countlsuk.h
new file mode 100644
index 00000000000000..7e860f5473920a
--- /dev/null
+++ b/libc/src/stdfix/countlsuk.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSUK_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSUK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlsuk(unsigned accum x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSUK_H
diff --git a/libc/src/stdfix/countlsulk.cpp b/libc/src/stdfix/countlsulk.cpp
new file mode 100644
index 00000000000000..7ad9be229cba26
--- /dev/null
+++ b/libc/src/stdfix/countlsulk.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlsulk.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlsulk, (unsigned long accum x)) {
+  return fixed_point::countls(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlsulk.h b/libc/src/stdfix/countlsulk.h
new file mode 100644
index 00000000000000..d3bca83f7d2717
--- /dev/null
+++ b/libc/src/stdfix/countlsulk.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSULK_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSULK_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlsulk(unsigned long accum x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSULK_H
diff --git a/libc/src/stdfix/countlsulr.cpp b/libc/src/stdfix/countlsulr.cpp
new file mode 100644
index 00000000000000..43605c0ab85ef1
--- /dev/null
+++ b/libc/src/stdfix/countlsulr.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlsulr.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlsulr, (unsigned long fract x)) {
+  return fixed_point::countls(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlsulr.h b/libc/src/stdfix/countlsulr.h
new file mode 100644
index 00000000000000..60fb22af869835
--- /dev/null
+++ b/libc/src/stdfix/countlsulr.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSULR_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSULR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlsulr(unsigned long fract x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSULR_H
diff --git a/libc/src/stdfix/countlsur.cpp b/libc/src/stdfix/countlsur.cpp
new file mode 100644
index 00000000000000..cf2e7c6731b664
--- /dev/null
+++ b/libc/src/stdfix/countlsur.cpp
@@ -0,0 +1,20 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "countlsur.h"
+#include "src/__support/common.h"
+#include "src/__support/fixed_point/fx_bits.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, countlsur, (unsigned fract x)) {
+  return fixed_point::countls(x);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/stdfix/countlsur.h b/libc/src/stdfix/countlsur.h
new file mode 100644
index 00000000000000..461ee1e87739c8
--- /dev/null
+++ b/libc/src/stdfix/countlsur.h
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_STDFIX_COUNTLSUR_H
+#define LLVM_LIBC_SRC_STDFIX_COUNTLSUR_H
+
+#include "include/llvm-libc-macros/stdfix-macros.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int countlsur(unsigned fract x);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_STDFIX_COUNTLSUR_H
diff --git a/libc/test/src/stdfix/CMakeLists.txt b/libc/test/src/stdfix/CMakeLists.txt
index 74a1fb13127cc3..2e1b8e1f6ab628 100644
--- a/libc/test/src/stdfix/CMakeLists.txt
+++ b/libc/test/src/stdfix/CMakeLists.txt
@@ -4,6 +4,23 @@ endif()
 
 add_custom_target(libc-stdfix-tests)
 
+foreach(suffix IN ITEMS hr r lr hk k lk uhr ur ulr uhk uk ulk)
+  add_libc_test(
+    countls${suffix}_test
+    SUITE
+      libc-stdfix-tests
+    HDRS
+      CountlsTest.h
+    SRCS
+      countls${suffix}_test.cpp
+    COMPILE_OPTIONS
+      -O3
+    DEPENDS
+      libc.src.stdfix.countls${suffix}
+      libc.src.__support.fixed_point.fx_rep
+  )
+endforeach()
+
 foreach(suffix IN ITEMS hr r lr hk k lk)
   add_libc_test(
     abs${suffix}_test
diff --git a/libc/test/src/stdfix/CountlsTest.h b/libc/test/src/stdfix/CountlsTest.h
new file mode 100644
index 00000000000000..64eeee2bf98077
--- /dev/null
+++ b/libc/test/src/stdfix/CountlsTest.h
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "test/UnitTest/Test.h"
+
+#include "src/__support/fixed_point/fx_rep.h"
+
+template <typename T> class CountlsTest : public LIBC_NAMESPACE::testing::Test {
+
+  using FXRep = LIBC_NAMESPACE::fixed_point::FXRep<T>;
+  static constexpr T zero = FXRep::ZERO();
+  static constexpr T max = FXRep::MAX();
+  static constexpr T min = FXRep::MIN();
+  static constexpr T one_half = FXRep::ONE_HALF();
+  static constexpr T one_fourth = FXRep::ONE_FOURTH();
+  static constexpr T eps = FXRep::EPS();
+
+public:
+  typedef int (*CountlsFunc)(T);
+
+  void testSpecialNumbers(CountlsFunc func) {
+    constexpr bool is_signed = (min != zero);
+
+    EXPECT_EQ(FXRep::INTEGRAL_LEN, func(one_half));
+    EXPECT_EQ(FXRep::INTEGRAL_LEN + 1, func(one_fourth));
+    EXPECT_EQ(FXRep::VALUE_LEN, func(zero));
+    EXPECT_EQ(FXRep::VALUE_LEN - 1, func(eps));
+    EXPECT_EQ(0, func(max));
+    // If signed, left shifting the minimum value will overflow, so countls = 0.
+    // If unsigned, the minimum value is zero, so countls is the number of value
+    // bits according to ISO/IEC TR 18037.
+    EXPECT_EQ(is_signed ? 0 : FXRep::VALUE_LEN, func(min));
+
+    if constexpr (is_signed) {
+      EXPECT_EQ(FXRep::VALUE_LEN, func(-eps));
+    }
+  }
+};
+
+#define LIST_COUNTLS_TESTS(T, func)                                            \
+  using LlvmLibcCountlsTest = CountlsTest<T>;                                  \
+  TEST_F(LlvmLibcCountlsTest, SpecialNumbers) { testSpecialNumbers(&func); }   \
+  static_assert(true, "Require semicolon.")
diff --git a/libc/test/src/stdfix/countlshk_test.cpp b/libc/test/src/stdfix/countlshk_test.cpp
new file mode 100644
index 00000000000000..5372c8fa572310
--- /dev/null
+++ b/libc/test/src/stdfix/countlshk_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlshk.h"
+
+LIST_COUNTLS_TESTS(short accum, LIBC_NAMESPACE::countlshk);
diff --git a/libc/test/src/stdfix/countlshr_test.cpp b/libc/test/src/stdfix/countlshr_test.cpp
new file mode 100644
index 00000000000000..3cec0d9fa2f97e
--- /dev/null
+++ b/libc/test/src/stdfix/countlshr_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlshr.h"
+
+LIST_COUNTLS_TESTS(short fract, LIBC_NAMESPACE::countlshr);
diff --git a/libc/test/src/stdfix/countlsk_test.cpp b/libc/test/src/stdfix/countlsk_test.cpp
new file mode 100644
index 00000000000000..0dd3b0006f6e75
--- /dev/null
+++ b/libc/test/src/stdfix/countlsk_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlsk.h"
+
+LIST_COUNTLS_TESTS(accum, LIBC_NAMESPACE::countlsk);
diff --git a/libc/test/src/stdfix/countlslk_test.cpp b/libc/test/src/stdfix/countlslk_test.cpp
new file mode 100644
index 00000000000000..d0f137bc0233dd
--- /dev/null
+++ b/libc/test/src/stdfix/countlslk_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlslk.h"
+
+LIST_COUNTLS_TESTS(long accum, LIBC_NAMESPACE::countlslk);
diff --git a/libc/test/src/stdfix/countlslr_test.cpp b/libc/test/src/stdfix/countlslr_test.cpp
new file mode 100644
index 00000000000000..94e063f41ec35f
--- /dev/null
+++ b/libc/test/src/stdfix/countlslr_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlslr.h"
+
+LIST_COUNTLS_TESTS(long fract, LIBC_NAMESPACE::countlslr);
diff --git a/libc/test/src/stdfix/countlsr_test.cpp b/libc/test/src/stdfix/countlsr_test.cpp
new file mode 100644
index 00000000000000..3fb44b312c8d6e
--- /dev/null
+++ b/libc/test/src/stdfix/countlsr_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlsr.h"
+
+LIST_COUNTLS_TESTS(fract, LIBC_NAMESPACE::countlsr);
diff --git a/libc/test/src/stdfix/countlsuhk_test.cpp b/libc/test/src/stdfix/countlsuhk_test.cpp
new file mode 100644
index 00000000000000..28e38eeb05aa67
--- /dev/null
+++ b/libc/test/src/stdfix/countlsuhk_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlsuhk.h"
+
+LIST_COUNTLS_TESTS(unsigned short accum, LIBC_NAMESPACE::countlsuhk);
diff --git a/libc/test/src/stdfix/countlsuhr_test.cpp b/libc/test/src/stdfix/countlsuhr_test.cpp
new file mode 100644
index 00000000000000..4647b4688ef807
--- /dev/null
+++ b/libc/test/src/stdfix/countlsuhr_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlsuhr.h"
+
+LIST_COUNTLS_TESTS(unsigned short fract, LIBC_NAMESPACE::countlsuhr);
diff --git a/libc/test/src/stdfix/countlsuk_test.cpp b/libc/test/src/stdfix/countlsuk_test.cpp
new file mode 100644
index 00000000000000..f2043ecc12acc7
--- /dev/null
+++ b/libc/test/src/stdfix/countlsuk_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlsuk.h"
+
+LIST_COUNTLS_TESTS(unsigned accum, LIBC_NAMESPACE::countlsuk);
diff --git a/libc/test/src/stdfix/countlsulk_test.cpp b/libc/test/src/stdfix/countlsulk_test.cpp
new file mode 100644
index 00000000000000..0158ccd4ff35cc
--- /dev/null
+++ b/libc/test/src/stdfix/countlsulk_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlsulk.h"
+
+LIST_COUNTLS_TESTS(unsigned long accum, LIBC_NAMESPACE::countlsulk);
diff --git a/libc/test/src/stdfix/countlsulr_test.cpp b/libc/test/src/stdfix/countlsulr_test.cpp
new file mode 100644
index 00000000000000..181b052319e92a
--- /dev/null
+++ b/libc/test/src/stdfix/countlsulr_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlsulr.h"
+
+LIST_COUNTLS_TESTS(unsigned long fract, LIBC_NAMESPACE::countlsulr);
diff --git a/libc/test/src/stdfix/countlsur_test.cpp b/libc/test/src/stdfix/countlsur_test.cpp
new file mode 100644
index 00000000000000..102f250b9b908d
--- /dev/null
+++ b/libc/test/src/stdfix/countlsur_test.cpp
@@ -0,0 +1,13 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "CountlsTest.h"
+
+#include "src/stdfix/countlsur.h"
+
+LIST_COUNTLS_TESTS(unsigned fract, LIBC_NAMESPACE::countlsur);



More information about the libc-commits mailing list