Skip to content

Commit 332ac18

Browse files
authored
[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.
1 parent 3eaf4a9 commit 332ac18

File tree

7 files changed

+69
-9
lines changed

7 files changed

+69
-9
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@ Non-comprehensive list of changes in this release
272272
``__builtin_signbit`` can now be used in constant expressions.
273273
- Plugins can now define custom attributes that apply to statements
274274
as well as declarations.
275+
- ``__builtin_abs`` function can now be used in constant expressions.
275276

276277
New Compiler Flags
277278
------------------

clang/include/clang/Basic/Builtins.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2714,6 +2714,7 @@ def Abs : IntMathTemplate, LibBuiltin<"stdlib.h"> {
27142714
let Attributes = [NoThrow, Const];
27152715
let Prototype = "T(T)";
27162716
let AddBuiltinPrefixedAlias = 1;
2717+
let OnlyBuiltinPrefixedAliasIsConstexpr = 1;
27172718
}
27182719

27192720
def Calloc : LibBuiltin<"stdlib.h"> {

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -563,6 +563,20 @@ static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC,
563563
return true;
564564
}
565565

566+
static bool interp__builtin_abs(InterpState &S, CodePtr OpPC,
567+
const InterpFrame *Frame, const Function *Func,
568+
const CallExpr *Call) {
569+
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
570+
APSInt Val = peekToAPSInt(S.Stk, ArgT);
571+
if (Val ==
572+
APSInt(APInt::getSignedMinValue(Val.getBitWidth()), /*IsUnsigned=*/false))
573+
return false;
574+
if (Val.isNegative())
575+
Val.negate();
576+
pushInteger(S, Val, Call->getType());
577+
return true;
578+
}
579+
566580
static bool interp__builtin_popcount(InterpState &S, CodePtr OpPC,
567581
const InterpFrame *Frame,
568582
const Function *Func,
@@ -1808,6 +1822,13 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
18081822
return false;
18091823
break;
18101824

1825+
case Builtin::BI__builtin_abs:
1826+
case Builtin::BI__builtin_labs:
1827+
case Builtin::BI__builtin_llabs:
1828+
if (!interp__builtin_abs(S, OpPC, Frame, F, Call))
1829+
return false;
1830+
break;
1831+
18111832
case Builtin::BI__builtin_popcount:
18121833
case Builtin::BI__builtin_popcountl:
18131834
case Builtin::BI__builtin_popcountll:

clang/lib/AST/ExprConstant.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13098,6 +13098,20 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
1309813098
return Success(Val.popcount() % 2, E);
1309913099
}
1310013100

13101+
case Builtin::BI__builtin_abs:
13102+
case Builtin::BI__builtin_labs:
13103+
case Builtin::BI__builtin_llabs: {
13104+
APSInt Val;
13105+
if (!EvaluateInteger(E->getArg(0), Val, Info))
13106+
return false;
13107+
if (Val == APSInt(APInt::getSignedMinValue(Val.getBitWidth()),
13108+
/*IsUnsigned=*/false))
13109+
return false;
13110+
if (Val.isNegative())
13111+
Val.negate();
13112+
return Success(Val, E);
13113+
}
13114+
1310113115
case Builtin::BI__builtin_popcount:
1310213116
case Builtin::BI__builtin_popcountl:
1310313117
case Builtin::BI__builtin_popcountll:

clang/test/AST/ByteCode/builtin-functions.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,20 @@ namespace fpclassify {
265265
char classify_subnorm [__builtin_fpclassify(-1, -1, -1, +1, -1, 1.0e-38f)];
266266
}
267267

268+
namespace abs {
269+
static_assert(__builtin_abs(14) == 14, "");
270+
static_assert(__builtin_labs(14L) == 14L, "");
271+
static_assert(__builtin_llabs(14LL) == 14LL, "");
272+
static_assert(__builtin_abs(-14) == 14, "");
273+
static_assert(__builtin_labs(-0x14L) == 0x14L, "");
274+
static_assert(__builtin_llabs(-0x141414141414LL) == 0x141414141414LL, "");
275+
#define BITSIZE(x) (sizeof(x) * 8)
276+
constexpr int abs4 = __builtin_abs(1 << (BITSIZE(int) - 1)); // both-error {{must be initialized by a constant expression}}
277+
constexpr long abs6 = __builtin_labs(1L << (BITSIZE(long) - 1)); // both-error {{must be initialized by a constant expression}}
278+
constexpr long long abs8 = __builtin_llabs(1LL << (BITSIZE(long long) - 1)); // both-error {{must be initialized by a constant expression}}
279+
#undef BITSIZE
280+
} // namespace abs
281+
268282
namespace fabs {
269283
static_assert(__builtin_fabs(-14.0) == 14.0, "");
270284
}

clang/test/CodeGenCXX/builtins.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ int o = X::__builtin_fabs(-2.0);
1414
long p = X::__builtin_fabsf(-3.0f);
1515
// CHECK: @p ={{.*}} global i64 3, align 8
1616

17+
int x = __builtin_abs(-2);
18+
// CHECK: @x ={{.*}} global i32 2, align 4
19+
20+
long y = __builtin_abs(-2l);
21+
// CHECK: @y ={{.*}} global i64 2, align 8
22+
1723
// PR8839
1824
extern "C" char memmove();
1925

@@ -52,14 +58,6 @@ extern "C" int __builtin_abs(int); // #1
5258
long __builtin_abs(long); // #2
5359
extern "C" int __builtin_abs(int); // #3
5460

55-
int x = __builtin_abs(-2);
56-
// CHECK: [[X:%.+]] = call i32 @llvm.abs.i32(i32 -2, i1 true)
57-
// CHECK-NEXT: store i32 [[X]], ptr @x, align 4
58-
59-
long y = __builtin_abs(-2l);
60-
// CHECK: [[Y:%.+]] = call noundef i64 @_Z13__builtin_absl(i64 noundef -2)
61-
// CHECK: store i64 [[Y]], ptr @y, align 8
62-
6361
extern const char char_memchr_arg[32];
6462
char *memchr_result = __builtin_char_memchr(char_memchr_arg, 123, 32);
6563
// CHECK: call ptr @memchr(ptr noundef @char_memchr_arg, i32 noundef 123, i64 noundef 32)

clang/test/Sema/constant-builtins-2.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ long double g11 = __builtin_nansl("");
3535
__float128 g11_2 = __builtin_nansf128("");
3636
#endif
3737

38-
//int g12 = __builtin_abs(-12);
38+
int g12 = __builtin_abs(-12);
3939

4040
double g13 = __builtin_fabs(-12.);
4141
double g13_0 = __builtin_fabs(-0.);
@@ -456,6 +456,17 @@ char clrsb9[__builtin_clrsb(1 << (BITSIZE(int) - 1)) == 0 ? 1 : -1];
456456
char clrsb10[__builtin_clrsb(~(1 << (BITSIZE(int) - 1))) == 0 ? 1 : -1];
457457
char clrsb11[__builtin_clrsb(0xf) == BITSIZE(int) - 5 ? 1 : -1];
458458
char clrsb12[__builtin_clrsb(~0x1f) == BITSIZE(int) - 6 ? 1 : -1];
459+
460+
char abs1[__builtin_abs(-12)];
461+
char abs2[__builtin_labs(-12L)];
462+
char abs3[__builtin_llabs(-12LL)];
463+
int abs4 = __builtin_abs(1 << (BITSIZE(int) - 1)); // expected-error {{not a compile-time constant}}
464+
char abs5[__builtin_abs((1 << (BITSIZE(int) - 1)) + 1)];
465+
long abs6 = __builtin_labs(1L << (BITSIZE(long) - 1)); // expected-error {{not a compile-time constant}}
466+
long abs7 = __builtin_labs((1L << (BITSIZE(long) - 1)) + 1);
467+
long long abs8 = __builtin_llabs(1LL << (BITSIZE(long long) - 1)); // expected-error {{not a compile-time constant}}
468+
long long abs9 = __builtin_llabs((1LL << (BITSIZE(long long) - 1)) + 1);
469+
459470
#undef BITSIZE
460471

461472
// GCC misc stuff

0 commit comments

Comments
 (0)