Skip to content
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

[libc] Make add_with_carry and sub_with_borrow constexpr. #81898

Merged
merged 1 commit into from
Feb 15, 2024

Conversation

lntue
Copy link
Contributor

@lntue lntue commented Feb 15, 2024

No description provided.

@llvmbot
Copy link
Collaborator

llvmbot commented Feb 15, 2024

@llvm/pr-subscribers-libc

Author: None (lntue)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/81898.diff

1 Files Affected:

  • (modified) libc/src/__support/math_extras.h (+84-46)
diff --git a/libc/src/__support/math_extras.h b/libc/src/__support/math_extras.h
index 8ec30396ffdb46..ae367994706c0f 100644
--- a/libc/src/__support/math_extras.h
+++ b/libc/src/__support/math_extras.h
@@ -56,11 +56,9 @@ add_with_carry_const(T a, T b, T carry_in) {
   return {sum, carry_out};
 }
 
-// This version is not always valid for constepxr because it's overriden below
-// if builtins are available.
 template <typename T>
-LIBC_INLINE cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T>,
-                             SumCarry<T>>
+LIBC_INLINE constexpr cpp::enable_if_t<
+    cpp::is_integral_v<T> && cpp::is_unsigned_v<T>, SumCarry<T>>
 add_with_carry(T a, T b, T carry_in) {
   return add_with_carry_const<T>(a, b, carry_in);
 }
@@ -69,48 +67,68 @@ add_with_carry(T a, T b, T carry_in) {
 // https://clang.llvm.org/docs/LanguageExtensions.html#multiprecision-arithmetic-builtins
 
 template <>
-LIBC_INLINE SumCarry<unsigned char>
+LIBC_INLINE constexpr SumCarry<unsigned char>
 add_with_carry<unsigned char>(unsigned char a, unsigned char b,
                               unsigned char carry_in) {
-  SumCarry<unsigned char> result{0, 0};
-  result.sum = __builtin_addcb(a, b, carry_in, &result.carry);
-  return result;
+  if (__builtin_is_constant_evaluated()) {
+    return add_with_carry_const<unsigned char>(a, b, carry_in);
+  } else {
+    SumCarry<unsigned char> result{0, 0};
+    result.sum = __builtin_addcb(a, b, carry_in, &result.carry);
+    return result;
+  }
 }
 
 template <>
-LIBC_INLINE SumCarry<unsigned short>
+LIBC_INLINE constexpr SumCarry<unsigned short>
 add_with_carry<unsigned short>(unsigned short a, unsigned short b,
                                unsigned short carry_in) {
-  SumCarry<unsigned short> result{0, 0};
-  result.sum = __builtin_addcs(a, b, carry_in, &result.carry);
-  return result;
+  if (__builtin_is_constant_evaluated()) {
+    return add_with_carry_const<unsigned short>(a, b, carry_in);
+  } else {
+    SumCarry<unsigned short> result{0, 0};
+    result.sum = __builtin_addcs(a, b, carry_in, &result.carry);
+    return result;
+  }
 }
 
 template <>
-LIBC_INLINE SumCarry<unsigned int>
+LIBC_INLINE constexpr SumCarry<unsigned int>
 add_with_carry<unsigned int>(unsigned int a, unsigned int b,
                              unsigned int carry_in) {
-  SumCarry<unsigned int> result{0, 0};
-  result.sum = __builtin_addc(a, b, carry_in, &result.carry);
-  return result;
+  if (__builtin_is_constant_evaluated()) {
+    return add_with_carry_const<unsigned int>(a, b, carry_in);
+  } else {
+    SumCarry<unsigned int> result{0, 0};
+    result.sum = __builtin_addc(a, b, carry_in, &result.carry);
+    return result;
+  }
 }
 
 template <>
-LIBC_INLINE SumCarry<unsigned long>
+LIBC_INLINE constexpr SumCarry<unsigned long>
 add_with_carry<unsigned long>(unsigned long a, unsigned long b,
                               unsigned long carry_in) {
-  SumCarry<unsigned long> result{0, 0};
-  result.sum = __builtin_addcl(a, b, carry_in, &result.carry);
-  return result;
+  if (__builtin_is_constant_evaluated()) {
+    return add_with_carry_const<unsigned long>(a, b, carry_in);
+  } else {
+    SumCarry<unsigned long> result{0, 0};
+    result.sum = __builtin_addcl(a, b, carry_in, &result.carry);
+    return result;
+  }
 }
 
 template <>
-LIBC_INLINE SumCarry<unsigned long long>
+LIBC_INLINE constexpr SumCarry<unsigned long long>
 add_with_carry<unsigned long long>(unsigned long long a, unsigned long long b,
                                    unsigned long long carry_in) {
-  SumCarry<unsigned long long> result{0, 0};
-  result.sum = __builtin_addcll(a, b, carry_in, &result.carry);
-  return result;
+  if (__builtin_is_constant_evaluated()) {
+    return add_with_carry_const<unsigned long long>(a, b, carry_in);
+  } else {
+    SumCarry<unsigned long long> result{0, 0};
+    result.sum = __builtin_addcll(a, b, carry_in, &result.carry);
+    return result;
+  }
 }
 
 #endif // LIBC_HAS_BUILTIN(__builtin_addc)
@@ -135,8 +153,8 @@ sub_with_borrow_const(T a, T b, T borrow_in) {
 // This version is not always valid for constepxr because it's overriden below
 // if builtins are available.
 template <typename T>
-LIBC_INLINE cpp::enable_if_t<cpp::is_integral_v<T> && cpp::is_unsigned_v<T>,
-                             DiffBorrow<T>>
+LIBC_INLINE constexpr cpp::enable_if_t<
+    cpp::is_integral_v<T> && cpp::is_unsigned_v<T>, DiffBorrow<T>>
 sub_with_borrow(T a, T b, T borrow_in) {
   return sub_with_borrow_const<T>(a, b, borrow_in);
 }
@@ -145,48 +163,68 @@ sub_with_borrow(T a, T b, T borrow_in) {
 // https://clang.llvm.org/docs/LanguageExtensions.html#multiprecision-arithmetic-builtins
 
 template <>
-LIBC_INLINE DiffBorrow<unsigned char>
+LIBC_INLINE constexpr DiffBorrow<unsigned char>
 sub_with_borrow<unsigned char>(unsigned char a, unsigned char b,
                                unsigned char borrow_in) {
-  DiffBorrow<unsigned char> result{0, 0};
-  result.diff = __builtin_subcb(a, b, borrow_in, &result.borrow);
-  return result;
+  if (__builtin_is_constant_evaluated()) {
+    return sub_with_borrow_const<unsigned char>(a, b, borrow_in);
+  } else {
+    DiffBorrow<unsigned char> result{0, 0};
+    result.diff = __builtin_subcb(a, b, borrow_in, &result.borrow);
+    return result;
+  }
 }
 
 template <>
-LIBC_INLINE DiffBorrow<unsigned short>
+LIBC_INLINE constexpr DiffBorrow<unsigned short>
 sub_with_borrow<unsigned short>(unsigned short a, unsigned short b,
                                 unsigned short borrow_in) {
-  DiffBorrow<unsigned short> result{0, 0};
-  result.diff = __builtin_subcs(a, b, borrow_in, &result.borrow);
-  return result;
+  if (__builtin_is_constant_evaluated()) {
+    return sub_with_borrow_const<unsigned short>(a, b, borrow_in);
+  } else {
+    DiffBorrow<unsigned short> result{0, 0};
+    result.diff = __builtin_subcs(a, b, borrow_in, &result.borrow);
+    return result;
+  }
 }
 
 template <>
-LIBC_INLINE DiffBorrow<unsigned int>
+LIBC_INLINE constexpr DiffBorrow<unsigned int>
 sub_with_borrow<unsigned int>(unsigned int a, unsigned int b,
                               unsigned int borrow_in) {
-  DiffBorrow<unsigned int> result{0, 0};
-  result.diff = __builtin_subc(a, b, borrow_in, &result.borrow);
-  return result;
+  if (__builtin_is_constant_evaluated()) {
+    return sub_with_borrow_const<unsigned int>(a, b, borrow_in);
+  } else {
+    DiffBorrow<unsigned int> result{0, 0};
+    result.diff = __builtin_subc(a, b, borrow_in, &result.borrow);
+    return result;
+  }
 }
 
 template <>
-LIBC_INLINE DiffBorrow<unsigned long>
+LIBC_INLINE constexpr DiffBorrow<unsigned long>
 sub_with_borrow<unsigned long>(unsigned long a, unsigned long b,
                                unsigned long borrow_in) {
-  DiffBorrow<unsigned long> result{0, 0};
-  result.diff = __builtin_subcl(a, b, borrow_in, &result.borrow);
-  return result;
+  if (__builtin_is_constant_evaluated()) {
+    return sub_with_borrow_const<unsigned long>(a, b, borrow_in);
+  } else {
+    DiffBorrow<unsigned long> result{0, 0};
+    result.diff = __builtin_subcl(a, b, borrow_in, &result.borrow);
+    return result;
+  }
 }
 
 template <>
-LIBC_INLINE DiffBorrow<unsigned long long>
+LIBC_INLINE constexpr DiffBorrow<unsigned long long>
 sub_with_borrow<unsigned long long>(unsigned long long a, unsigned long long b,
                                     unsigned long long borrow_in) {
-  DiffBorrow<unsigned long long> result{0, 0};
-  result.diff = __builtin_subcll(a, b, borrow_in, &result.borrow);
-  return result;
+  if (__builtin_is_constant_evaluated()) {
+    return sub_with_borrow_const<unsigned long long>(a, b, borrow_in);
+  } else {
+    DiffBorrow<unsigned long long> result{0, 0};
+    result.diff = __builtin_subcll(a, b, borrow_in, &result.borrow);
+    return result;
+  }
 }
 
 #endif // LIBC_HAS_BUILTIN(__builtin_subc)

SumCarry<unsigned char> result{0, 0};
result.sum = __builtin_addcb(a, b, carry_in, &result.carry);
return result;
if (__builtin_is_constant_evaluated()) {
Copy link
Contributor

Choose a reason for hiding this comment

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

does this builtin need a guard to check if it's available?

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've checked on godbolt, and seems like it works fine on clang 9.0+ and gcc 11+ in all x86-64, arm32, and riscv-32

Copy link
Member

@nickdesaulniers nickdesaulniers left a comment

Choose a reason for hiding this comment

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

Neat, TIL about __builtin_is_constant_evaluated.

Copy link
Contributor

@michaelrj-google michaelrj-google left a comment

Choose a reason for hiding this comment

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

LGTM

@lntue lntue merged commit 495c57f into llvm:main Feb 15, 2024
6 checks passed
@lntue lntue deleted the constexpr branch February 15, 2024 19:00
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.

None yet

4 participants