[clang] 332ac18 - [clang] constexpr built-in abs function. (#112539)

via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 18 04:03:54 PDT 2024


Author: c8ef
Date: 2024-10-18T19:03:50+08:00
New Revision: 332ac18e318ce0b6bf316d7f35d33d8af4c56fc5

URL: https://github.com/llvm/llvm-project/commit/332ac18e318ce0b6bf316d7f35d33d8af4c56fc5
DIFF: https://github.com/llvm/llvm-project/commit/332ac18e318ce0b6bf316d7f35d33d8af4c56fc5.diff

LOG: [clang] constexpr built-in abs function. (#112539)

According to [P0533R9](https://wg21.link/P0533R9), the C++ standard
library functions corresponding to the C macros in `[c.math.abs]` are
now `constexpr`.

To implement this feature in libc++, we must make the built-in abs
function `constexpr`. This patch adds the implementation of a
`constexpr` abs function for the current constant evaluator and the new
bytecode interpreter.

It is important to note that in 2's complement systems, the absolute
value of the most negative value is out of range. In gcc, it will result
in an out-of-range error and will not be evaluated as constants. We
follow the same approach here.

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/include/clang/Basic/Builtins.td
    clang/lib/AST/ByteCode/InterpBuiltin.cpp
    clang/lib/AST/ExprConstant.cpp
    clang/test/AST/ByteCode/builtin-functions.cpp
    clang/test/CodeGenCXX/builtins.cpp
    clang/test/Sema/constant-builtins-2.c

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index a65bd6f382901b..b34da2d755704a 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -272,6 +272,7 @@ Non-comprehensive list of changes in this release
   ``__builtin_signbit`` can now be used in constant expressions.
 - Plugins can now define custom attributes that apply to statements
   as well as declarations.
+- ``__builtin_abs`` function can now be used in constant expressions.
 
 New Compiler Flags
 ------------------

diff  --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 382fb6b7a3c031..90475a361bb8f8 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -2714,6 +2714,7 @@ def Abs : IntMathTemplate, LibBuiltin<"stdlib.h"> {
   let Attributes = [NoThrow, Const];
   let Prototype = "T(T)";
   let AddBuiltinPrefixedAlias = 1;
+  let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
 }
 
 def Calloc : LibBuiltin<"stdlib.h"> {

diff  --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 65c7b4e5306d72..d4a8e6c2035ee5 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -563,6 +563,20 @@ static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC,
   return true;
 }
 
+static bool interp__builtin_abs(InterpState &S, CodePtr OpPC,
+                                const InterpFrame *Frame, const Function *Func,
+                                const CallExpr *Call) {
+  PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
+  APSInt Val = peekToAPSInt(S.Stk, ArgT);
+  if (Val ==
+      APSInt(APInt::getSignedMinValue(Val.getBitWidth()), /*IsUnsigned=*/false))
+    return false;
+  if (Val.isNegative())
+    Val.negate();
+  pushInteger(S, Val, Call->getType());
+  return true;
+}
+
 static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
                                      const InterpFrame *Frame,
                                      const Function *Func,
@@ -1808,6 +1822,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
       return false;
     break;
 
+  case Builtin::BI__builtin_abs:
+  case Builtin::BI__builtin_labs:
+  case Builtin::BI__builtin_llabs:
+    if (!interp__builtin_abs(S, OpPC, Frame, F, Call))
+      return false;
+    break;
+
   case Builtin::BI__builtin_popcount:
   case Builtin::BI__builtin_popcountl:
   case Builtin::BI__builtin_popcountll:

diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 8544052d5e4924..8e36cad2d2c6e7 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -13098,6 +13098,20 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
     return Success(Val.popcount() % 2, E);
   }
 
+  case Builtin::BI__builtin_abs:
+  case Builtin::BI__builtin_labs:
+  case Builtin::BI__builtin_llabs: {
+    APSInt Val;
+    if (!EvaluateInteger(E->getArg(0), Val, Info))
+      return false;
+    if (Val == APSInt(APInt::getSignedMinValue(Val.getBitWidth()),
+                      /*IsUnsigned=*/false))
+      return false;
+    if (Val.isNegative())
+      Val.negate();
+    return Success(Val, E);
+  }
+
   case Builtin::BI__builtin_popcount:
   case Builtin::BI__builtin_popcountl:
   case Builtin::BI__builtin_popcountll:

diff  --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index 450ff5671314db..b5d334178f8213 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -265,6 +265,20 @@ namespace fpclassify {
   char classify_subnorm [__builtin_fpclassify(-1, -1, -1, +1, -1, 1.0e-38f)];
 }
 
+namespace abs {
+  static_assert(__builtin_abs(14) == 14, "");
+  static_assert(__builtin_labs(14L) == 14L, "");
+  static_assert(__builtin_llabs(14LL) == 14LL, "");
+  static_assert(__builtin_abs(-14) == 14, "");
+  static_assert(__builtin_labs(-0x14L) == 0x14L, "");
+  static_assert(__builtin_llabs(-0x141414141414LL) == 0x141414141414LL, "");
+#define BITSIZE(x) (sizeof(x) * 8)
+  constexpr int abs4 = __builtin_abs(1 << (BITSIZE(int) - 1)); // both-error {{must be initialized by a constant expression}}
+  constexpr long abs6 = __builtin_labs(1L << (BITSIZE(long) - 1)); // both-error {{must be initialized by a constant expression}}
+  constexpr long long abs8 = __builtin_llabs(1LL << (BITSIZE(long long) - 1)); // both-error {{must be initialized by a constant expression}}
+#undef BITSIZE
+} // namespace abs
+
 namespace fabs {
   static_assert(__builtin_fabs(-14.0) == 14.0, "");
 }

diff  --git a/clang/test/CodeGenCXX/builtins.cpp b/clang/test/CodeGenCXX/builtins.cpp
index 90265186fb3d8c..37f9491d12d04b 100644
--- a/clang/test/CodeGenCXX/builtins.cpp
+++ b/clang/test/CodeGenCXX/builtins.cpp
@@ -14,6 +14,12 @@ int o = X::__builtin_fabs(-2.0);
 long p = X::__builtin_fabsf(-3.0f);
 // CHECK: @p ={{.*}} global i64 3, align 8
 
+int x = __builtin_abs(-2);
+// CHECK: @x ={{.*}} global i32 2, align 4
+
+long y = __builtin_abs(-2l);
+// CHECK: @y ={{.*}} global i64 2, align 8
+
 // PR8839
 extern "C" char memmove();
 
@@ -52,14 +58,6 @@ extern "C" int __builtin_abs(int); // #1
 long __builtin_abs(long);          // #2
 extern "C" int __builtin_abs(int); // #3
 
-int x = __builtin_abs(-2);
-// CHECK:      [[X:%.+]] = call i32 @llvm.abs.i32(i32 -2, i1 true)
-// CHECK-NEXT: store i32 [[X]], ptr @x, align 4
-
-long y = __builtin_abs(-2l);
-// CHECK:  [[Y:%.+]] = call noundef i64 @_Z13__builtin_absl(i64 noundef -2)
-// CHECK:  store i64 [[Y]], ptr @y, align 8
-
 extern const char char_memchr_arg[32];
 char *memchr_result = __builtin_char_memchr(char_memchr_arg, 123, 32);
 // CHECK: call ptr @memchr(ptr noundef @char_memchr_arg, i32 noundef 123, i64 noundef 32)

diff  --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c
index da2264500d7680..e465a3c5f0ad86 100644
--- a/clang/test/Sema/constant-builtins-2.c
+++ b/clang/test/Sema/constant-builtins-2.c
@@ -35,7 +35,7 @@ long double  g11 = __builtin_nansl("");
 __float128   g11_2 = __builtin_nansf128("");
 #endif
 
-//int          g12 = __builtin_abs(-12);
+int g12 = __builtin_abs(-12);
 
 double       g13 = __builtin_fabs(-12.);
 double       g13_0 = __builtin_fabs(-0.);
@@ -456,6 +456,17 @@ char clrsb9[__builtin_clrsb(1 << (BITSIZE(int) - 1)) == 0 ? 1 : -1];
 char clrsb10[__builtin_clrsb(~(1 << (BITSIZE(int) - 1))) == 0 ? 1 : -1];
 char clrsb11[__builtin_clrsb(0xf) == BITSIZE(int) - 5 ? 1 : -1];
 char clrsb12[__builtin_clrsb(~0x1f) == BITSIZE(int) - 6 ? 1 : -1];
+
+char abs1[__builtin_abs(-12)];
+char abs2[__builtin_labs(-12L)];
+char abs3[__builtin_llabs(-12LL)];
+int abs4 = __builtin_abs(1 << (BITSIZE(int) - 1)); // expected-error {{not a compile-time constant}}
+char abs5[__builtin_abs((1 << (BITSIZE(int) - 1)) + 1)];
+long abs6 = __builtin_labs(1L << (BITSIZE(long) - 1)); // expected-error {{not a compile-time constant}}
+long abs7 = __builtin_labs((1L << (BITSIZE(long) - 1)) + 1);
+long long abs8 = __builtin_llabs(1LL << (BITSIZE(long long) - 1)); // expected-error {{not a compile-time constant}}
+long long abs9 = __builtin_llabs((1LL << (BITSIZE(long long) - 1)) + 1);
+
 #undef BITSIZE
 
 // GCC misc stuff


        


More information about the cfe-commits mailing list