Skip to content

[libc][stdbit] implement stdc_first_leading_one (C23) #81502

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 14, 2024

Conversation

nickdesaulniers
Copy link
Member

No description provided.

@llvmbot llvmbot added the libc label Feb 12, 2024
@llvmbot
Copy link
Member

llvmbot commented Feb 12, 2024

@llvm/pr-subscribers-libc

Author: Nick Desaulniers (nickdesaulniers)

Changes

Patch is 25.09 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/81502.diff

24 Files Affected:

  • (modified) libc/config/linux/x86_64/entrypoints.txt (+5)
  • (modified) libc/docs/stdbit.rst (+20-20)
  • (modified) libc/include/llvm-libc-macros/stdbit-macros.h (+22)
  • (modified) libc/spec/stdc.td (+8-2)
  • (modified) libc/src/__support/CPP/bit.h (+29)
  • (modified) libc/src/stdbit/CMakeLists.txt (+1)
  • (added) libc/src/stdbit/stdc_first_leading_one_uc.cpp (+20)
  • (added) libc/src/stdbit/stdc_first_leading_one_uc.h (+18)
  • (added) libc/src/stdbit/stdc_first_leading_one_ui.cpp (+20)
  • (added) libc/src/stdbit/stdc_first_leading_one_ui.h (+18)
  • (added) libc/src/stdbit/stdc_first_leading_one_ul.cpp (+20)
  • (added) libc/src/stdbit/stdc_first_leading_one_ul.h (+18)
  • (added) libc/src/stdbit/stdc_first_leading_one_ull.cpp (+21)
  • (added) libc/src/stdbit/stdc_first_leading_one_ull.h (+18)
  • (added) libc/src/stdbit/stdc_first_leading_one_us.cpp (+21)
  • (added) libc/src/stdbit/stdc_first_leading_one_us.h (+18)
  • (modified) libc/test/include/stdbit_test.cpp (+15)
  • (modified) libc/test/src/__support/CPP/bit_test.cpp (+7)
  • (modified) libc/test/src/stdbit/CMakeLists.txt (+1)
  • (added) libc/test/src/stdbit/stdc_first_leading_one_uc_test.cpp (+21)
  • (added) libc/test/src/stdbit/stdc_first_leading_one_ui_test.cpp (+21)
  • (added) libc/test/src/stdbit/stdc_first_leading_one_ul_test.cpp (+21)
  • (added) libc/test/src/stdbit/stdc_first_leading_one_ull_test.cpp (+21)
  • (added) libc/test/src/stdbit/stdc_first_leading_one_us_test.cpp (+21)
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 75e39ae51fdb06..fc30bcf56665c7 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -117,6 +117,11 @@ set(TARGET_LIBC_ENTRYPOINTS
     libc.src.stdbit.stdc_first_leading_zero_ui
     libc.src.stdbit.stdc_first_leading_zero_ul
     libc.src.stdbit.stdc_first_leading_zero_ull
+    libc.src.stdbit.stdc_first_leading_one_uc
+    libc.src.stdbit.stdc_first_leading_one_us
+    libc.src.stdbit.stdc_first_leading_one_ui
+    libc.src.stdbit.stdc_first_leading_one_ul
+    libc.src.stdbit.stdc_first_leading_one_ull
 
     # stdlib.h entrypoints
     libc.src.stdlib.abs
diff --git a/libc/docs/stdbit.rst b/libc/docs/stdbit.rst
index 4f242d21f8b842..c4e49a8228683e 100644
--- a/libc/docs/stdbit.rst
+++ b/libc/docs/stdbit.rst
@@ -41,26 +41,26 @@ stdc_leading_ones_us         |check|
 stdc_leading_ones_ui         |check|
 stdc_leading_ones_ul         |check|
 stdc_leading_ones_ull        |check|
-stdc_trailing_zeros_uc
-stdc_trailing_zeros_us
-stdc_trailing_zeros_ui
-stdc_trailing_zeros_ul
-stdc_trailing_zeros_ull
-stdc_trailing_ones_uc
-stdc_trailing_ones_us
-stdc_trailing_ones_ui
-stdc_trailing_ones_ul
-stdc_trailing_ones_ull
-stdc_first_leading_zero_uc
-stdc_first_leading_zero_us
-stdc_first_leading_zero_ui
-stdc_first_leading_zero_ul
-stdc_first_leading_zero_ull
-stdc_first_leading_one_uc
-stdc_first_leading_one_us
-stdc_first_leading_one_ui
-stdc_first_leading_one_ul
-stdc_first_leading_one_ull
+stdc_trailing_zeros_uc       |check|
+stdc_trailing_zeros_us       |check|
+stdc_trailing_zeros_ui       |check|
+stdc_trailing_zeros_ul       |check|
+stdc_trailing_zeros_ull      |check|
+stdc_trailing_ones_uc        |check|
+stdc_trailing_ones_us        |check|
+stdc_trailing_ones_ui        |check|
+stdc_trailing_ones_ul        |check|
+stdc_trailing_ones_ull       |check|
+stdc_first_leading_zero_uc   |check|
+stdc_first_leading_zero_us   |check|
+stdc_first_leading_zero_ui   |check|
+stdc_first_leading_zero_ul   |check|
+stdc_first_leading_zero_ull  |check|
+stdc_first_leading_one_uc    |check|
+stdc_first_leading_one_us    |check|
+stdc_first_leading_one_ui    |check|
+stdc_first_leading_one_ul    |check|
+stdc_first_leading_one_ull   |check|
 stdc_first_trailing_zero_uc
 stdc_first_trailing_zero_us
 stdc_first_trailing_zero_ui
diff --git a/libc/include/llvm-libc-macros/stdbit-macros.h b/libc/include/llvm-libc-macros/stdbit-macros.h
index 693a45e63419ff..87c590e61e3999 100644
--- a/libc/include/llvm-libc-macros/stdbit-macros.h
+++ b/libc/include/llvm-libc-macros/stdbit-macros.h
@@ -86,6 +86,21 @@ inline unsigned stdc_first_leading_zero(unsigned long x) {
 inline unsigned stdc_first_leading_zero(unsigned long long x) {
   return stdc_first_leading_zero_ull(x);
 }
+inline unsigned stdc_first_leading_one(unsigned char x) {
+  return stdc_first_leading_one_uc(x);
+}
+inline unsigned stdc_first_leading_one(unsigned short x) {
+  return stdc_first_leading_one_us(x);
+}
+inline unsigned stdc_first_leading_one(unsigned x) {
+  return stdc_first_leading_one_ui(x);
+}
+inline unsigned stdc_first_leading_one(unsigned long x) {
+  return stdc_first_leading_one_ul(x);
+}
+inline unsigned stdc_first_leading_one(unsigned long long x) {
+  return stdc_first_leading_one_ull(x);
+}
 #else
 #define stdc_leading_zeros(x)                                                  \
   _Generic((x),                                                                \
@@ -122,6 +137,13 @@ inline unsigned stdc_first_leading_zero(unsigned long long x) {
       unsigned: stdc_first_leading_zero_ui,                                    \
       unsigned long: stdc_first_leading_zero_ul,                               \
       unsigned long long: stdc_first_leading_zero_ull)(x)
+#define stdc_first_leading_one(x)                                              \
+  _Generic((x),                                                                \
+      unsigned char: stdc_first_leading_one_uc,                                \
+      unsigned short: stdc_first_leading_one_us,                               \
+      unsigned: stdc_first_leading_one_ui,                                     \
+      unsigned long: stdc_first_leading_one_ul,                                \
+      unsigned long long: stdc_first_leading_one_ull)(x)
 #endif // __cplusplus
 
 #endif // __LLVM_LIBC_MACROS_STDBIT_MACROS_H
diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td
index 1720a4a3c3aaf9..5e87831b907fb5 100644
--- a/libc/spec/stdc.td
+++ b/libc/spec/stdc.td
@@ -781,7 +781,8 @@ def StdC : StandardSpec<"stdc"> {
         Macro<"stdc_leading_ones">,
         Macro<"stdc_trailing_zeros">,
         Macro<"stdc_trailing_ones">,
-        Macro<"stdc_first_leading_zero">
+        Macro<"stdc_first_leading_zero">,
+        Macro<"stdc_first_leading_one">
       ], // Macros
       [], // Types
       [], // Enumerations
@@ -810,7 +811,12 @@ def StdC : StandardSpec<"stdc"> {
           FunctionSpec<"stdc_first_leading_zero_us", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedShortType>]>,
           FunctionSpec<"stdc_first_leading_zero_ui", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedIntType>]>,
           FunctionSpec<"stdc_first_leading_zero_ul", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongType>]>,
-          FunctionSpec<"stdc_first_leading_zero_ull", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongLongType>]>
+          FunctionSpec<"stdc_first_leading_zero_ull", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongLongType>]>,
+          FunctionSpec<"stdc_first_leading_one_uc", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedCharType>]>,
+          FunctionSpec<"stdc_first_leading_one_us", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedShortType>]>,
+          FunctionSpec<"stdc_first_leading_one_ui", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedIntType>]>,
+          FunctionSpec<"stdc_first_leading_one_ul", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongType>]>,
+          FunctionSpec<"stdc_first_leading_one_ull", RetValSpec<UnsignedIntType>, [ArgSpec<UnsignedLongLongType>]>
       ] // Functions
   >;
 
diff --git a/libc/src/__support/CPP/bit.h b/libc/src/__support/CPP/bit.h
index 392fbe248138ae..579a2b514a6ddf 100644
--- a/libc/src/__support/CPP/bit.h
+++ b/libc/src/__support/CPP/bit.h
@@ -268,6 +268,35 @@ SPECIALIZE_FLZ(first_leading_zero, unsigned long long, __builtin_clzll)
 
 #undef SPECIALIZE_FLZ
 
+#define SPECIALIZE_FLO(NAME, TYPE, BUILTIN)                                    \
+  template <> [[nodiscard]] LIBC_INLINE constexpr int NAME<TYPE>(TYPE value) { \
+    static_assert(cpp::is_unsigned_v<TYPE>);                                   \
+    return value == static_cast<TYPE>(0)                                       \
+               ? 0                                                             \
+               : BUILTIN(static_cast<TYPE>(value)) + 1;                        \
+  }
+
+template <typename T, typename = cpp::enable_if_t<cpp::is_unsigned_v<T>>>
+[[nodiscard]] LIBC_INLINE constexpr int first_leading_one(T value) {
+  return value == static_cast<T>(0) ? 0
+                                    : countl_zero<T>(static_cast<T>(value)) + 1;
+}
+
+#if LIBC_HAS_BUILTIN(__builtin_clzs)
+SPECIALIZE_FLO(first_leading_one, unsigned short, __builtin_clzs)
+#endif
+#if LIBC_HAS_BUILTIN(__builtin_clz)
+SPECIALIZE_FLO(first_leading_one, unsigned int, __builtin_clz)
+#endif
+#if LIBC_HAS_BUILTIN(__builtin_clzl)
+SPECIALIZE_FLO(first_leading_one, unsigned long, __builtin_clzl)
+#endif
+#if LIBC_HAS_BUILTIN(__builtin_clzll)
+SPECIALIZE_FLO(first_leading_one, unsigned long long, __builtin_clzll)
+#endif
+
+#undef SPECIALIZE_FLO
+
 } // namespace LIBC_NAMESPACE::cpp
 
 #endif // LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
diff --git a/libc/src/stdbit/CMakeLists.txt b/libc/src/stdbit/CMakeLists.txt
index 65d5f344307475..6ee93861b8db40 100644
--- a/libc/src/stdbit/CMakeLists.txt
+++ b/libc/src/stdbit/CMakeLists.txt
@@ -4,6 +4,7 @@ set(prefixes
   trailing_zeros
   trailing_ones
   first_leading_zero
+  first_leading_one
 )
 set(suffixes c s i l ll)
 foreach(prefix IN LISTS prefixes)
diff --git a/libc/src/stdbit/stdc_first_leading_one_uc.cpp b/libc/src/stdbit/stdc_first_leading_one_uc.cpp
new file mode 100644
index 00000000000000..02871595fdb6b8
--- /dev/null
+++ b/libc/src/stdbit/stdc_first_leading_one_uc.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of stdc_first_leading_one_uc -----------------------===//
+//
+// 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 "src/stdbit/stdc_first_leading_one_uc.h"
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(unsigned, stdc_first_leading_one_uc, (unsigned char value)) {
+  return static_cast<unsigned>(cpp::first_leading_one(value));
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdbit/stdc_first_leading_one_uc.h b/libc/src/stdbit/stdc_first_leading_one_uc.h
new file mode 100644
index 00000000000000..58892c3f0ff298
--- /dev/null
+++ b/libc/src/stdbit/stdc_first_leading_one_uc.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for stdc_first_leading_one_uc -----*- C++ -*-===//
+//
+// 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_STDBIT_STDC_FIRST_LEADING_ONE_UC_H
+#define LLVM_LIBC_SRC_STDBIT_STDC_FIRST_LEADING_ONE_UC_H
+
+namespace LIBC_NAMESPACE {
+
+unsigned stdc_first_leading_one_uc(unsigned char value);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDBIT_STDC_FIRST_LEADING_ONE_UC_H
diff --git a/libc/src/stdbit/stdc_first_leading_one_ui.cpp b/libc/src/stdbit/stdc_first_leading_one_ui.cpp
new file mode 100644
index 00000000000000..a6c7ef5a833914
--- /dev/null
+++ b/libc/src/stdbit/stdc_first_leading_one_ui.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of stdc_first_leading_one_ui -----------------------===//
+//
+// 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 "src/stdbit/stdc_first_leading_one_ui.h"
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(unsigned, stdc_first_leading_one_ui, (unsigned value)) {
+  return static_cast<unsigned>(cpp::first_leading_one(value));
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdbit/stdc_first_leading_one_ui.h b/libc/src/stdbit/stdc_first_leading_one_ui.h
new file mode 100644
index 00000000000000..613adf4e1ff762
--- /dev/null
+++ b/libc/src/stdbit/stdc_first_leading_one_ui.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for stdc_first_leading_one_ui -----*- C++ -*-===//
+//
+// 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_STDBIT_STDC_FIRST_LEADING_ONE_UI_H
+#define LLVM_LIBC_SRC_STDBIT_STDC_FIRST_LEADING_ONE_UI_H
+
+namespace LIBC_NAMESPACE {
+
+unsigned stdc_first_leading_one_ui(unsigned value);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDBIT_STDC_FIRST_LEADING_ONE_UI_H
diff --git a/libc/src/stdbit/stdc_first_leading_one_ul.cpp b/libc/src/stdbit/stdc_first_leading_one_ul.cpp
new file mode 100644
index 00000000000000..d1bcab5dda02a9
--- /dev/null
+++ b/libc/src/stdbit/stdc_first_leading_one_ul.cpp
@@ -0,0 +1,20 @@
+//===-- Implementation of stdc_first_leading_one_ul -----------------------===//
+//
+// 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 "src/stdbit/stdc_first_leading_one_ul.h"
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(unsigned, stdc_first_leading_one_ul, (unsigned long value)) {
+  return static_cast<unsigned>(cpp::first_leading_one(value));
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdbit/stdc_first_leading_one_ul.h b/libc/src/stdbit/stdc_first_leading_one_ul.h
new file mode 100644
index 00000000000000..47c179f3fbacd1
--- /dev/null
+++ b/libc/src/stdbit/stdc_first_leading_one_ul.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for stdc_first_leading_one_ul -----*- C++ -*-===//
+//
+// 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_STDBIT_STDC_FIRST_LEADING_ONE_UL_H
+#define LLVM_LIBC_SRC_STDBIT_STDC_FIRST_LEADING_ONE_UL_H
+
+namespace LIBC_NAMESPACE {
+
+unsigned stdc_first_leading_one_ul(unsigned long value);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDBIT_STDC_FIRST_LEADING_ONE_UL_H
diff --git a/libc/src/stdbit/stdc_first_leading_one_ull.cpp b/libc/src/stdbit/stdc_first_leading_one_ull.cpp
new file mode 100644
index 00000000000000..7be8f1051ec231
--- /dev/null
+++ b/libc/src/stdbit/stdc_first_leading_one_ull.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of stdc_first_leading_one_ull ----------------------===//
+//
+// 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 "src/stdbit/stdc_first_leading_one_ull.h"
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(unsigned, stdc_first_leading_one_ull,
+                   (unsigned long long value)) {
+  return static_cast<unsigned>(cpp::first_leading_one(value));
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdbit/stdc_first_leading_one_ull.h b/libc/src/stdbit/stdc_first_leading_one_ull.h
new file mode 100644
index 00000000000000..344d03f7100f47
--- /dev/null
+++ b/libc/src/stdbit/stdc_first_leading_one_ull.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for stdc_first_leading_one_ull ----*- C++ -*-===//
+//
+// 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_STDBIT_STDC_FIRST_LEADING_ONE_ULL_H
+#define LLVM_LIBC_SRC_STDBIT_STDC_FIRST_LEADING_ONE_ULL_H
+
+namespace LIBC_NAMESPACE {
+
+unsigned stdc_first_leading_one_ull(unsigned long long value);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDBIT_STDC_FIRST_LEADING_ONE_ULL_H
diff --git a/libc/src/stdbit/stdc_first_leading_one_us.cpp b/libc/src/stdbit/stdc_first_leading_one_us.cpp
new file mode 100644
index 00000000000000..7a4c7e673f367f
--- /dev/null
+++ b/libc/src/stdbit/stdc_first_leading_one_us.cpp
@@ -0,0 +1,21 @@
+//===-- Implementation of stdc_first_leading_one_us -----------------------===//
+//
+// 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 "src/stdbit/stdc_first_leading_one_us.h"
+
+#include "src/__support/CPP/bit.h"
+#include "src/__support/common.h"
+
+namespace LIBC_NAMESPACE {
+
+LLVM_LIBC_FUNCTION(unsigned, stdc_first_leading_one_us,
+                   (unsigned short value)) {
+  return static_cast<unsigned>(cpp::first_leading_one(value));
+}
+
+} // namespace LIBC_NAMESPACE
diff --git a/libc/src/stdbit/stdc_first_leading_one_us.h b/libc/src/stdbit/stdc_first_leading_one_us.h
new file mode 100644
index 00000000000000..9d5feaf1e92f08
--- /dev/null
+++ b/libc/src/stdbit/stdc_first_leading_one_us.h
@@ -0,0 +1,18 @@
+//===-- Implementation header for stdc_first_leading_one_us -----*- C++ -*-===//
+//
+// 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_STDBIT_STDC_FIRST_LEADING_ONE_US_H
+#define LLVM_LIBC_SRC_STDBIT_STDC_FIRST_LEADING_ONE_US_H
+
+namespace LIBC_NAMESPACE {
+
+unsigned stdc_first_leading_one_us(unsigned short value);
+
+} // namespace LIBC_NAMESPACE
+
+#endif // LLVM_LIBC_SRC_STDBIT_STDC_FIRST_LEADING_ONE_US_H
diff --git a/libc/test/include/stdbit_test.cpp b/libc/test/include/stdbit_test.cpp
index 9a66a76de20bc5..c2fbcb8ce2d321 100644
--- a/libc/test/include/stdbit_test.cpp
+++ b/libc/test/include/stdbit_test.cpp
@@ -50,6 +50,13 @@ unsigned stdc_first_leading_zero_ul(unsigned long) noexcept { return 0xEDU; }
 unsigned stdc_first_leading_zero_ull(unsigned long long) noexcept {
   return 0xEFU;
 }
+unsigned stdc_first_leading_one_uc(unsigned char) noexcept { return 0xFAU; }
+unsigned stdc_first_leading_one_us(unsigned short) noexcept { return 0xFBU; }
+unsigned stdc_first_leading_one_ui(unsigned) noexcept { return 0xFCU; }
+unsigned stdc_first_leading_one_ul(unsigned long) noexcept { return 0xFDU; }
+unsigned stdc_first_leading_one_ull(unsigned long long) noexcept {
+  return 0xFFU;
+}
 }
 
 #include "include/llvm-libc-macros/stdbit-macros.h"
@@ -93,3 +100,11 @@ TEST(LlvmLibcStdbitTest, TypeGenericMacroFirstLeadingZero) {
   EXPECT_EQ(stdc_first_leading_zero(0UL), 0xEDU);
   EXPECT_EQ(stdc_first_leading_zero(0ULL), 0xEFU);
 }
+
+TEST(LlvmLibcStdbitTest, TypeGenericMacroFirstLeadingOne) {
+  EXPECT_EQ(stdc_first_leading_one(static_cast<unsigned char>(0U)), 0xFAU);
+  EXPECT_EQ(stdc_first_leading_one(static_cast<unsigned short>(0U)), 0xFBU);
+  EXPECT_EQ(stdc_first_leading_one(0U), 0xFCU);
+  EXPECT_EQ(stdc_first_leading_one(0UL), 0xFDU);
+  EXPECT_EQ(stdc_first_leading_one(0ULL), 0xFFU);
+}
diff --git a/libc/test/src/__support/CPP/bit_test.cpp b/libc/test/src/__support/CPP/bit_test.cpp
index 00d8ca5d293ace..a70726d4feb241 100644
--- a/libc/test/src/__support/CPP/bit_test.cpp
+++ b/libc/test/src/__support/CPP/bit_test.cpp
@@ -213,4 +213,11 @@ TYPED_TEST(LlvmLibcBitTest, FirstLeadingZero, UnsignedTypes) {
               cpp::numeric_limits<T>::digits - i);
 }
 
+TYPED_TEST(LlvmLibcBitTest, FirstLeadingOne, UnsignedTypes) {
+  EXPECT_EQ(first_leading_one<T>(static_cast<T>(0)), 0);
+  for (int i = 0U; i != cpp::numeric_limits<T>::digits; ++i)
+    EXPECT_EQ(first_leading_one<T>(T(1) << i),
+              cpp::numeric_limits<T>::digits - i);
+}
+
 } // namespace LIBC_NAMESPACE::cpp
diff --git a/libc/test/src/stdbit/CMakeLists.txt b/libc/test/src/stdbit/CMakeLists.txt
index bc7e49d186a0d5..e32663f88e8620 100644
--- a/libc/test/src/stdbit/CMakeLists.txt
+++ b/libc/test/src/stdbit/CMakeLists.txt
@@ -6,6 +6,7 @@ set(prefixes
   trailing_zeros
   trailing_ones
   first_leading_zero
+  first_leading_one
 )
 set(suffixes c s i l ll)
 foreach(prefix IN LISTS prefixes)
diff --git a/libc/test/src/stdbit/stdc_first_leading_one_uc_test.cpp b/libc/test/src/stdbit/stdc_first_leading_one_uc_test.cpp
new file mode 100644
index 00000000000000..b8c8db587098e4
--- /dev/null
+++ b/libc/test/src/stdbit/stdc_first_leading_one_uc_test.cpp
@@ -0,0 +1,21 @@
+//===-- Unittests for stdc_first_l...
[truncated]

@@ -268,6 +268,11 @@ SPECIALIZE_FLZ(first_leading_zero, unsigned long long, __builtin_clzll)

#undef SPECIALIZE_FLZ

template <typename T, typename = cpp::enable_if_t<cpp::is_unsigned_v<T>>>
[[nodiscard]] LIBC_INLINE constexpr int first_leading_one(T value) {
return !value ? 0 : countl_zero<T>(static_cast<T>(value)) + 1;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be better to define first_leading_one as first_leading_zero(~value)?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for the static_cast<T> here since the value is already of the right type.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be better to define first_leading_one as first_leading_zero(~value)?

Yes. acb2d5a

No need for the static_cast here since the value is already of the right type.

In which case (using unary negation) the cast is necessary since the unary negation will result in implicit promotion for types smaller than int. We want to then truncate back to the correct size before calling first_leading_zero.

Copy link
Contributor

@gchatelet gchatelet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a little nit, otherwise LGTM

@nickdesaulniers nickdesaulniers merged commit 6059671 into llvm:main Feb 14, 2024
@nickdesaulniers nickdesaulniers deleted the first_leading_one branch February 14, 2024 17:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants