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

via libc-commits libc-commits at lists.llvm.org
Tue Nov 5 13:50:29 PST 2024


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

>From cc87a9ac973131db1047a22ebfb2b0db2d2f1926 Mon Sep 17 00:00:00 2001
From: Duncan <duncpro at icloud.com>
Date: Tue, 29 Oct 2024 22:33:41 -0400
Subject: [PATCH 1/3] [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/docs/math/stdfix.rst                     |  2 +-
 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      | 31 ++++++-
 libc/src/__support/fixed_point/fx_rep.h       | 12 +++
 libc/src/stdfix/CMakeLists.txt                | 12 +++
 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           | 15 ++++
 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 +++
 49 files changed, 912 insertions(+), 2 deletions(-)
 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/docs/math/stdfix.rst b/libc/docs/math/stdfix.rst
index d8dcb0cfa4c521..ebf19ba722c8a4 100644
--- a/libc/docs/math/stdfix.rst
+++ b/libc/docs/math/stdfix.rst
@@ -73,7 +73,7 @@ The following functions are included in the ISO/IEC TR 18037:2008 standard.
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
 | \*bits        |                |             |               |            |                |             |                |             |               |            |                |             |
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
-| countls       |                |             |               |            |                |             |                |             |               |            |                |             |
+| countls       | |check|        | |check|     | |check|       | |check|    | |check|        | |check|     | |check|        | |check|     | |check|       | |check|    | |check|        | |check|     |
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
 | divi          |                |             |               |            |                |             |                |             |               |            |                |             |
 +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
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..7f195ab0ba20b8 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"
@@ -50,6 +51,11 @@ template <typename T> struct FXBits {
   static constexpr StorageType SIGN_MASK =
       (fx_rep::SIGN_LEN == 0 ? 0 : StorageType(1) << SIGN_OFFSET);
 
+  // The integral and fraction bits, but not the sign bit nor the padding bits.
+  static constexpr StorageType VALUE_MASK = INTEGRAL_MASK | FRACTION_MASK;
+  // The integral, fraction, and sign bits, but not the padding bits.
+  static constexpr StorageType TOTAL_MASK = SIGN_MASK | VALUE_MASK;
+
 public:
   LIBC_INLINE constexpr FXBits() = default;
 
@@ -66,6 +72,12 @@ template <typename T> struct FXBits {
     }
   }
 
+  // Returns the complete bitstring representation of the fixed-point number.
+  // The bitstring is of the form `padding | sign | integral | fraction`.
+  LIBC_INLINE constexpr StorageType get_bits() {
+    return (value & TOTAL_MASK) >> FRACTION_OFFSET;
+  }
+
   LIBC_INLINE constexpr StorageType get_fraction() {
     return (value & FRACTION_MASK) >> FRACTION_OFFSET;
   }
@@ -142,6 +154,23 @@ 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 = bit_not(x);
+  }
+
+  BitType value_bits = FXBits<T>(x).get_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..ee80be4073e0c3 100644
--- a/libc/src/stdfix/CMakeLists.txt
+++ b/libc/src/stdfix/CMakeLists.txt
@@ -42,6 +42,18 @@ foreach(suffix IN ITEMS hr r lr hk k lk uhr ur ulr uhk uk ulk)
     DEPENDS
       libc.src.__support.fixed_point.fx_bits
   )
+
+  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()
 
 add_entrypoint_object(
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..a59261f270b892 100644
--- a/libc/test/src/stdfix/CMakeLists.txt
+++ b/libc/test/src/stdfix/CMakeLists.txt
@@ -57,6 +57,21 @@ foreach(suffix IN ITEMS hr r lr hk k lk uhr ur ulr uhk uk ulk)
       libc.src.stdfix.round${suffix}
       libc.src.__support.fixed_point.fx_bits
   )
+
+  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()
 
 add_libc_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);

>From 1d0488a6fa8735b1bb8dc08a561eaf40e64ce581 Mon Sep 17 00:00:00 2001
From: Duncan <duncpro at icloud.com>
Date: Tue, 5 Nov 2024 15:55:47 -0500
Subject: [PATCH 2/3] replace repeated FXRep::VALUE_LEN constant declaration
 with single template function

---
 libc/src/__support/fixed_point/fx_bits.h |  2 +-
 libc/src/__support/fixed_point/fx_rep.h  | 16 +++++-----------
 libc/test/src/stdfix/CountlsTest.h       | 10 ++++++----
 3 files changed, 12 insertions(+), 16 deletions(-)

diff --git a/libc/src/__support/fixed_point/fx_bits.h b/libc/src/__support/fixed_point/fx_bits.h
index 7f195ab0ba20b8..0df1e44f71f18a 100644
--- a/libc/src/__support/fixed_point/fx_bits.h
+++ b/libc/src/__support/fixed_point/fx_bits.h
@@ -160,7 +160,7 @@ 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;
+  constexpr int PADDING_LEN = CONTAIN_LEN - get_value_len<FXRep>();
 
   if constexpr (FXRep::SIGN_LEN != 0) {
     if (x < 0)
diff --git a/libc/src/__support/fixed_point/fx_rep.h b/libc/src/__support/fixed_point/fx_rep.h
index f1321e6a629ee5..f98bec01d3e69c 100644
--- a/libc/src/__support/fixed_point/fx_rep.h
+++ b/libc/src/__support/fixed_point/fx_rep.h
@@ -45,7 +45,6 @@ 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; }
@@ -66,7 +65,6 @@ 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; }
@@ -87,7 +85,6 @@ 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; }
@@ -108,7 +105,6 @@ 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; }
@@ -129,7 +125,6 @@ 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; }
@@ -150,7 +145,6 @@ 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; }
@@ -171,7 +165,6 @@ 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; }
@@ -192,7 +185,6 @@ 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; }
@@ -213,7 +205,6 @@ 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; }
@@ -234,7 +225,6 @@ 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; }
@@ -276,7 +266,6 @@ 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; }
@@ -307,6 +296,11 @@ template <> struct FXRep<unsigned sat accum> : FXRep<unsigned accum> {};
 template <>
 struct FXRep<unsigned long sat accum> : FXRep<unsigned long accum> {};
 
+template<typename FXRep>
+constexpr int get_value_len() {
+  return FXRep::INTEGRAL_LEN + FXRep::FRACTION_LEN; 
+}
+
 } // namespace fixed_point
 } // namespace LIBC_NAMESPACE_DECL
 
diff --git a/libc/test/src/stdfix/CountlsTest.h b/libc/test/src/stdfix/CountlsTest.h
index 64eeee2bf98077..4ed773a542086c 100644
--- a/libc/test/src/stdfix/CountlsTest.h
+++ b/libc/test/src/stdfix/CountlsTest.h
@@ -20,6 +20,8 @@ template <typename T> class CountlsTest : public LIBC_NAMESPACE::testing::Test {
   static constexpr T one_fourth = FXRep::ONE_FOURTH();
   static constexpr T eps = FXRep::EPS();
 
+  static constexpr auto value_len = LIBC_NAMESPACE::fixed_point::get_value_len<FXRep>();
+
 public:
   typedef int (*CountlsFunc)(T);
 
@@ -28,16 +30,16 @@ template <typename T> class CountlsTest : public LIBC_NAMESPACE::testing::Test {
 
     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(value_len, func(zero));
+    EXPECT_EQ(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));
+    EXPECT_EQ(is_signed ? 0 : value_len, func(min));
 
     if constexpr (is_signed) {
-      EXPECT_EQ(FXRep::VALUE_LEN, func(-eps));
+      EXPECT_EQ(value_len, func(-eps));
     }
   }
 };

>From e73b2a20c1f04f8c0c184279cc90ecf963781ef0 Mon Sep 17 00:00:00 2001
From: Duncan <duncpro at icloud.com>
Date: Tue, 5 Nov 2024 16:50:15 -0500
Subject: [PATCH 3/3] add explicit negative/non-negative integer test cases,
 and explicit negative fractional test cases

---
 libc/test/src/stdfix/CountlsTest.h | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/libc/test/src/stdfix/CountlsTest.h b/libc/test/src/stdfix/CountlsTest.h
index 4ed773a542086c..67252e7ad5381f 100644
--- a/libc/test/src/stdfix/CountlsTest.h
+++ b/libc/test/src/stdfix/CountlsTest.h
@@ -26,7 +26,7 @@ template <typename T> class CountlsTest : public LIBC_NAMESPACE::testing::Test {
   typedef int (*CountlsFunc)(T);
 
   void testSpecialNumbers(CountlsFunc func) {
-    constexpr bool is_signed = (min != zero);
+    constexpr bool is_signed = (FXRep::SIGN_LEN > 0);
 
     EXPECT_EQ(FXRep::INTEGRAL_LEN, func(one_half));
     EXPECT_EQ(FXRep::INTEGRAL_LEN + 1, func(one_fourth));
@@ -38,8 +38,20 @@ template <typename T> class CountlsTest : public LIBC_NAMESPACE::testing::Test {
     // bits according to ISO/IEC TR 18037.
     EXPECT_EQ(is_signed ? 0 : value_len, func(min));
 
+    if (10 <= static_cast<int>(max)) {
+      EXPECT_EQ(FXRep::INTEGRAL_LEN - 4, func(10));
+    }
+    
+    if (static_cast<int>(min) <= -10) {
+      EXPECT_EQ(FXRep::INTEGRAL_LEN - 4, func(-10));
+    }
+
     if constexpr (is_signed) {
       EXPECT_EQ(value_len, func(-eps));
+      EXPECT_EQ(FXRep::INTEGRAL_LEN + 1, func(-one_half));
+      if (FXRep::FRACTION_LEN >= 2) {
+        EXPECT_EQ(FXRep::INTEGRAL_LEN + 2, func(-one_fourth));
+      }
     }
   }
 };



More information about the libc-commits mailing list