From 11259343593043c77678b59d420159fcd147a858 Mon Sep 17 00:00:00 2001 From: Mital Ashok Date: Sun, 18 Aug 2024 10:50:42 +0100 Subject: [PATCH] [Clang] `constexpr` builtin floating point classification / comparison functions (#94118) As per [P0533R9](https://wg21.link/P0533R9), the corresponding C++ `[c.math.fpclass]` standard library functions for the C macros are now `constexpr`. The only classification function that wasn't already `constexpr` was `__builtin_signbit`. The floating point comparison functions `__builtin_isgreater`, `__builtin_isgreaterequal`, `__builtin_isless`, `__builtin_islessequal`, `__builtin_islessgreater` and `__builtin_isunordered` are now `constexpr`. The C23 macro `iseqsig` is not currently supported because `__bulitin_iseqsig` doesn't exist yet (and C++26 is still currently based on C18). This also allows them to be constant folded in C, matching the behaviour of GCC. --- clang/docs/ReleaseNotes.rst | 4 + clang/include/clang/Basic/Builtins.td | 20 ++-- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 60 +++++++++++ clang/lib/AST/ExprConstant.cpp | 48 +++++++++ clang/test/Analysis/builtin_signbit.cpp | 126 ++++++++++------------- clang/test/Sema/constant-builtins-2.c | 48 +++++++++ 6 files changed, 224 insertions(+), 82 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ffdd063ec99037..12a3707db8a39f 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -161,6 +161,10 @@ C23 Feature Support Non-comprehensive list of changes in this release ------------------------------------------------- +- The floating point comparison builtins (``__builtin_isgreater``, + ``__builtin_isgreaterequal``, ``__builtin_isless``, etc.) and + ``__builtin_signbit`` 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 0a874d8638df43..036366cdadf4aa 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -533,42 +533,42 @@ def BuiltinComplex : Builtin { def IsGreater : Builtin { let Spellings = ["__builtin_isgreater"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, - CustomTypeChecking]; + CustomTypeChecking, Constexpr]; let Prototype = "int(...)"; } def IsGreaterEqual : Builtin { let Spellings = ["__builtin_isgreaterequal"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, - CustomTypeChecking]; + CustomTypeChecking, Constexpr]; let Prototype = "int(...)"; } def IsLess : Builtin { let Spellings = ["__builtin_isless"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, - CustomTypeChecking]; + CustomTypeChecking, Constexpr]; let Prototype = "int(...)"; } def IsLessEqual : Builtin { let Spellings = ["__builtin_islessequal"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, - CustomTypeChecking]; + CustomTypeChecking, Constexpr]; let Prototype = "int(...)"; } def IsLessGreater : Builtin { let Spellings = ["__builtin_islessgreater"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, - CustomTypeChecking]; + CustomTypeChecking, Constexpr]; let Prototype = "int(...)"; } def IsUnordered : Builtin { let Spellings = ["__builtin_isunordered"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, - CustomTypeChecking]; + CustomTypeChecking, Constexpr]; let Prototype = "int(...)"; } @@ -646,19 +646,21 @@ def IsFPClass : Builtin { def Signbit : Builtin { let Spellings = ["__builtin_signbit"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, - CustomTypeChecking]; + CustomTypeChecking, Constexpr]; let Prototype = "int(...)"; } def SignbitF : Builtin { let Spellings = ["__builtin_signbitf"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, + Constexpr]; let Prototype = "int(float)"; } def SignbitL : Builtin { let Spellings = ["__builtin_signbitl"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, + Constexpr]; let Prototype = "int(long double)"; } diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index c3370e2e5286e0..26abf582051067 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -433,6 +433,51 @@ static bool interp__builtin_iszero(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_signbit(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, const Function *F, + const CallExpr *Call) { + const Floating &Arg = S.Stk.peek(); + + pushInteger(S, Arg.isNegative(), Call->getType()); + return true; +} + +static bool interp_floating_comparison(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const Function *F, + const CallExpr *Call) { + const Floating &RHS = S.Stk.peek(); + const Floating &LHS = S.Stk.peek(align(2u * primSize(PT_Float))); + unsigned ID = F->getBuiltinID(); + + pushInteger( + S, + [&] { + switch (ID) { + case Builtin::BI__builtin_isgreater: + return LHS > RHS; + case Builtin::BI__builtin_isgreaterequal: + return LHS >= RHS; + case Builtin::BI__builtin_isless: + return LHS < RHS; + case Builtin::BI__builtin_islessequal: + return LHS <= RHS; + case Builtin::BI__builtin_islessgreater: { + ComparisonCategoryResult cmp = LHS.compare(RHS); + return cmp == ComparisonCategoryResult::Less || + cmp == ComparisonCategoryResult::Greater; + } + case Builtin::BI__builtin_isunordered: + return LHS.compare(RHS) == ComparisonCategoryResult::Unordered; + default: + llvm_unreachable("Unexpected builtin ID: Should be a floating point " + "comparison function"); + } + }(), + Call->getType()); + return true; +} + /// First parameter to __builtin_isfpclass is the floating value, the /// second one is an integral value. static bool interp__builtin_isfpclass(InterpState &S, CodePtr OpPC, @@ -1313,6 +1358,21 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, if (!interp__builtin_iszero(S, OpPC, Frame, F, Call)) return false; break; + case Builtin::BI__builtin_signbit: + case Builtin::BI__builtin_signbitf: + case Builtin::BI__builtin_signbitl: + if (!interp__builtin_signbit(S, OpPC, Frame, F, Call)) + return false; + break; + case Builtin::BI__builtin_isgreater: + case Builtin::BI__builtin_isgreaterequal: + case Builtin::BI__builtin_isless: + case Builtin::BI__builtin_islessequal: + case Builtin::BI__builtin_islessgreater: + case Builtin::BI__builtin_isunordered: + if (!interp_floating_comparison(S, OpPC, Frame, F, Call)) + return false; + break; case Builtin::BI__builtin_isfpclass: if (!interp__builtin_isfpclass(S, OpPC, Frame, F, Call)) return false; diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 7bfc63ffd81e28..31b65ff4bcc135 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12833,6 +12833,54 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, Success(Val.isZero() ? 1 : 0, E); } + case Builtin::BI__builtin_signbit: + case Builtin::BI__builtin_signbitf: + case Builtin::BI__builtin_signbitl: { + APFloat Val(0.0); + return EvaluateFloat(E->getArg(0), Val, Info) && + Success(Val.isNegative() ? 1 : 0, E); + } + + case Builtin::BI__builtin_isgreater: + case Builtin::BI__builtin_isgreaterequal: + case Builtin::BI__builtin_isless: + case Builtin::BI__builtin_islessequal: + case Builtin::BI__builtin_islessgreater: + case Builtin::BI__builtin_isunordered: { + APFloat LHS(0.0); + APFloat RHS(0.0); + if (!EvaluateFloat(E->getArg(0), LHS, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + + return Success( + [&] { + switch (BuiltinOp) { + case Builtin::BI__builtin_isgreater: + return LHS > RHS; + case Builtin::BI__builtin_isgreaterequal: + return LHS >= RHS; + case Builtin::BI__builtin_isless: + return LHS < RHS; + case Builtin::BI__builtin_islessequal: + return LHS <= RHS; + case Builtin::BI__builtin_islessgreater: { + APFloat::cmpResult cmp = LHS.compare(RHS); + return cmp == APFloat::cmpResult::cmpLessThan || + cmp == APFloat::cmpResult::cmpGreaterThan; + } + case Builtin::BI__builtin_isunordered: + return LHS.compare(RHS) == APFloat::cmpResult::cmpUnordered; + default: + llvm_unreachable("Unexpected builtin ID: Should be a floating " + "point comparison function"); + } + }() + ? 1 + : 0, + E); + } + case Builtin::BI__builtin_issignaling: { APFloat Val(0.0); return EvaluateFloat(E->getArg(0), Val, Info) && diff --git a/clang/test/Analysis/builtin_signbit.cpp b/clang/test/Analysis/builtin_signbit.cpp index be10f0950f69b7..ad185d855cfff3 100644 --- a/clang/test/Analysis/builtin_signbit.cpp +++ b/clang/test/Analysis/builtin_signbit.cpp @@ -12,103 +12,83 @@ long double ld = -1.0L; // CHECK-BE32-LABEL: define dso_local void @_Z12test_signbitv( // CHECK-BE32-SAME: ) #[[ATTR0:[0-9]+]] { // CHECK-BE32-NEXT: entry: -// CHECK-BE32-NEXT: [[TMP0:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64 -// CHECK-BE32-NEXT: [[TMP1:%.*]] = trunc i128 [[TMP0]] to i64 -// CHECK-BE32-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP1]], 0 -// CHECK-BE32-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP2]] to i8 +// CHECK-BE32-NEXT: store i8 0, ptr @b, align 1 +// CHECK-BE32-NEXT: [[TMP0:%.*]] = load ppc_fp128, ptr @ld, align 16 +// CHECK-BE32-NEXT: [[TMP1:%.*]] = bitcast ppc_fp128 [[TMP0]] to i128 +// CHECK-BE32-NEXT: [[TMP2:%.*]] = lshr i128 [[TMP1]], 64 +// CHECK-BE32-NEXT: [[TMP3:%.*]] = trunc i128 [[TMP2]] to i64 +// CHECK-BE32-NEXT: [[TMP4:%.*]] = icmp slt i64 [[TMP3]], 0 +// CHECK-BE32-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP4]] to i8 // CHECK-BE32-NEXT: store i8 [[FROMBOOL]], ptr @b, align 1 -// CHECK-BE32-NEXT: [[TMP3:%.*]] = load ppc_fp128, ptr @ld, align 16 -// CHECK-BE32-NEXT: [[TMP4:%.*]] = bitcast ppc_fp128 [[TMP3]] to i128 -// CHECK-BE32-NEXT: [[TMP5:%.*]] = lshr i128 [[TMP4]], 64 -// CHECK-BE32-NEXT: [[TMP6:%.*]] = trunc i128 [[TMP5]] to i64 -// CHECK-BE32-NEXT: [[TMP7:%.*]] = icmp slt i64 [[TMP6]], 0 +// CHECK-BE32-NEXT: store i8 0, ptr @b, align 1 +// CHECK-BE32-NEXT: [[TMP5:%.*]] = load double, ptr @d, align 8 +// CHECK-BE32-NEXT: [[CONV:%.*]] = fptrunc double [[TMP5]] to float +// CHECK-BE32-NEXT: [[TMP6:%.*]] = bitcast float [[CONV]] to i32 +// CHECK-BE32-NEXT: [[TMP7:%.*]] = icmp slt i32 [[TMP6]], 0 // CHECK-BE32-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP7]] to i8 // CHECK-BE32-NEXT: store i8 [[FROMBOOL1]], ptr @b, align 1 // CHECK-BE32-NEXT: store i8 0, ptr @b, align 1 -// CHECK-BE32-NEXT: [[TMP8:%.*]] = load double, ptr @d, align 8 -// CHECK-BE32-NEXT: [[CONV:%.*]] = fptrunc double [[TMP8]] to float -// CHECK-BE32-NEXT: [[TMP9:%.*]] = bitcast float [[CONV]] to i32 -// CHECK-BE32-NEXT: [[TMP10:%.*]] = icmp slt i32 [[TMP9]], 0 -// CHECK-BE32-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP10]] to i8 +// CHECK-BE32-NEXT: [[TMP8:%.*]] = load ppc_fp128, ptr @ld, align 16 +// CHECK-BE32-NEXT: [[TMP9:%.*]] = bitcast ppc_fp128 [[TMP8]] to i128 +// CHECK-BE32-NEXT: [[TMP10:%.*]] = lshr i128 [[TMP9]], 64 +// CHECK-BE32-NEXT: [[TMP11:%.*]] = trunc i128 [[TMP10]] to i64 +// CHECK-BE32-NEXT: [[TMP12:%.*]] = icmp slt i64 [[TMP11]], 0 +// CHECK-BE32-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP12]] to i8 // CHECK-BE32-NEXT: store i8 [[FROMBOOL2]], ptr @b, align 1 -// CHECK-BE32-NEXT: [[TMP11:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64 -// CHECK-BE32-NEXT: [[TMP12:%.*]] = trunc i128 [[TMP11]] to i64 -// CHECK-BE32-NEXT: [[TMP13:%.*]] = icmp slt i64 [[TMP12]], 0 -// CHECK-BE32-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[TMP13]] to i8 -// CHECK-BE32-NEXT: store i8 [[FROMBOOL3]], ptr @b, align 1 -// CHECK-BE32-NEXT: [[TMP14:%.*]] = load ppc_fp128, ptr @ld, align 16 -// CHECK-BE32-NEXT: [[TMP15:%.*]] = bitcast ppc_fp128 [[TMP14]] to i128 -// CHECK-BE32-NEXT: [[TMP16:%.*]] = lshr i128 [[TMP15]], 64 -// CHECK-BE32-NEXT: [[TMP17:%.*]] = trunc i128 [[TMP16]] to i64 -// CHECK-BE32-NEXT: [[TMP18:%.*]] = icmp slt i64 [[TMP17]], 0 -// CHECK-BE32-NEXT: [[FROMBOOL4:%.*]] = zext i1 [[TMP18]] to i8 -// CHECK-BE32-NEXT: store i8 [[FROMBOOL4]], ptr @b, align 1 // CHECK-BE32-NEXT: ret void // // CHECK-BE64-LABEL: define dso_local void @_Z12test_signbitv( // CHECK-BE64-SAME: ) #[[ATTR0:[0-9]+]] { // CHECK-BE64-NEXT: entry: -// CHECK-BE64-NEXT: [[TMP0:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64 -// CHECK-BE64-NEXT: [[TMP1:%.*]] = trunc i128 [[TMP0]] to i64 -// CHECK-BE64-NEXT: [[TMP2:%.*]] = icmp slt i64 [[TMP1]], 0 -// CHECK-BE64-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP2]] to i8 +// CHECK-BE64-NEXT: store i8 0, ptr @b, align 1 +// CHECK-BE64-NEXT: [[TMP0:%.*]] = load ppc_fp128, ptr @ld, align 16 +// CHECK-BE64-NEXT: [[TMP1:%.*]] = bitcast ppc_fp128 [[TMP0]] to i128 +// CHECK-BE64-NEXT: [[TMP2:%.*]] = lshr i128 [[TMP1]], 64 +// CHECK-BE64-NEXT: [[TMP3:%.*]] = trunc i128 [[TMP2]] to i64 +// CHECK-BE64-NEXT: [[TMP4:%.*]] = icmp slt i64 [[TMP3]], 0 +// CHECK-BE64-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP4]] to i8 // CHECK-BE64-NEXT: store i8 [[FROMBOOL]], ptr @b, align 1 -// CHECK-BE64-NEXT: [[TMP3:%.*]] = load ppc_fp128, ptr @ld, align 16 -// CHECK-BE64-NEXT: [[TMP4:%.*]] = bitcast ppc_fp128 [[TMP3]] to i128 -// CHECK-BE64-NEXT: [[TMP5:%.*]] = lshr i128 [[TMP4]], 64 -// CHECK-BE64-NEXT: [[TMP6:%.*]] = trunc i128 [[TMP5]] to i64 -// CHECK-BE64-NEXT: [[TMP7:%.*]] = icmp slt i64 [[TMP6]], 0 +// CHECK-BE64-NEXT: store i8 0, ptr @b, align 1 +// CHECK-BE64-NEXT: [[TMP5:%.*]] = load double, ptr @d, align 8 +// CHECK-BE64-NEXT: [[CONV:%.*]] = fptrunc double [[TMP5]] to float +// CHECK-BE64-NEXT: [[TMP6:%.*]] = bitcast float [[CONV]] to i32 +// CHECK-BE64-NEXT: [[TMP7:%.*]] = icmp slt i32 [[TMP6]], 0 // CHECK-BE64-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP7]] to i8 // CHECK-BE64-NEXT: store i8 [[FROMBOOL1]], ptr @b, align 1 // CHECK-BE64-NEXT: store i8 0, ptr @b, align 1 -// CHECK-BE64-NEXT: [[TMP8:%.*]] = load double, ptr @d, align 8 -// CHECK-BE64-NEXT: [[CONV:%.*]] = fptrunc double [[TMP8]] to float -// CHECK-BE64-NEXT: [[TMP9:%.*]] = bitcast float [[CONV]] to i32 -// CHECK-BE64-NEXT: [[TMP10:%.*]] = icmp slt i32 [[TMP9]], 0 -// CHECK-BE64-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP10]] to i8 +// CHECK-BE64-NEXT: [[TMP8:%.*]] = load ppc_fp128, ptr @ld, align 16 +// CHECK-BE64-NEXT: [[TMP9:%.*]] = bitcast ppc_fp128 [[TMP8]] to i128 +// CHECK-BE64-NEXT: [[TMP10:%.*]] = lshr i128 [[TMP9]], 64 +// CHECK-BE64-NEXT: [[TMP11:%.*]] = trunc i128 [[TMP10]] to i64 +// CHECK-BE64-NEXT: [[TMP12:%.*]] = icmp slt i64 [[TMP11]], 0 +// CHECK-BE64-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP12]] to i8 // CHECK-BE64-NEXT: store i8 [[FROMBOOL2]], ptr @b, align 1 -// CHECK-BE64-NEXT: [[TMP11:%.*]] = lshr i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128), 64 -// CHECK-BE64-NEXT: [[TMP12:%.*]] = trunc i128 [[TMP11]] to i64 -// CHECK-BE64-NEXT: [[TMP13:%.*]] = icmp slt i64 [[TMP12]], 0 -// CHECK-BE64-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[TMP13]] to i8 -// CHECK-BE64-NEXT: store i8 [[FROMBOOL3]], ptr @b, align 1 -// CHECK-BE64-NEXT: [[TMP14:%.*]] = load ppc_fp128, ptr @ld, align 16 -// CHECK-BE64-NEXT: [[TMP15:%.*]] = bitcast ppc_fp128 [[TMP14]] to i128 -// CHECK-BE64-NEXT: [[TMP16:%.*]] = lshr i128 [[TMP15]], 64 -// CHECK-BE64-NEXT: [[TMP17:%.*]] = trunc i128 [[TMP16]] to i64 -// CHECK-BE64-NEXT: [[TMP18:%.*]] = icmp slt i64 [[TMP17]], 0 -// CHECK-BE64-NEXT: [[FROMBOOL4:%.*]] = zext i1 [[TMP18]] to i8 -// CHECK-BE64-NEXT: store i8 [[FROMBOOL4]], ptr @b, align 1 // CHECK-BE64-NEXT: ret void // // CHECK-LE-LABEL: define dso_local void @_Z12test_signbitv( // CHECK-LE-SAME: ) #[[ATTR0:[0-9]+]] { // CHECK-LE-NEXT: entry: -// CHECK-LE-NEXT: [[TMP0:%.*]] = icmp slt i64 trunc (i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128) to i64), 0 -// CHECK-LE-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP0]] to i8 +// CHECK-LE-NEXT: store i8 0, ptr @b, align 1 +// CHECK-LE-NEXT: [[TMP0:%.*]] = load ppc_fp128, ptr @ld, align 16 +// CHECK-LE-NEXT: [[TMP1:%.*]] = bitcast ppc_fp128 [[TMP0]] to i128 +// CHECK-LE-NEXT: [[TMP2:%.*]] = trunc i128 [[TMP1]] to i64 +// CHECK-LE-NEXT: [[TMP3:%.*]] = icmp slt i64 [[TMP2]], 0 +// CHECK-LE-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TMP3]] to i8 // CHECK-LE-NEXT: store i8 [[FROMBOOL]], ptr @b, align 1 -// CHECK-LE-NEXT: [[TMP1:%.*]] = load ppc_fp128, ptr @ld, align 16 -// CHECK-LE-NEXT: [[TMP2:%.*]] = bitcast ppc_fp128 [[TMP1]] to i128 -// CHECK-LE-NEXT: [[TMP3:%.*]] = trunc i128 [[TMP2]] to i64 -// CHECK-LE-NEXT: [[TMP4:%.*]] = icmp slt i64 [[TMP3]], 0 -// CHECK-LE-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP4]] to i8 +// CHECK-LE-NEXT: store i8 0, ptr @b, align 1 +// CHECK-LE-NEXT: [[TMP4:%.*]] = load double, ptr @d, align 8 +// CHECK-LE-NEXT: [[CONV:%.*]] = fptrunc double [[TMP4]] to float +// CHECK-LE-NEXT: [[TMP5:%.*]] = bitcast float [[CONV]] to i32 +// CHECK-LE-NEXT: [[TMP6:%.*]] = icmp slt i32 [[TMP5]], 0 +// CHECK-LE-NEXT: [[FROMBOOL1:%.*]] = zext i1 [[TMP6]] to i8 // CHECK-LE-NEXT: store i8 [[FROMBOOL1]], ptr @b, align 1 // CHECK-LE-NEXT: store i8 0, ptr @b, align 1 -// CHECK-LE-NEXT: [[TMP5:%.*]] = load double, ptr @d, align 8 -// CHECK-LE-NEXT: [[CONV:%.*]] = fptrunc double [[TMP5]] to float -// CHECK-LE-NEXT: [[TMP6:%.*]] = bitcast float [[CONV]] to i32 -// CHECK-LE-NEXT: [[TMP7:%.*]] = icmp slt i32 [[TMP6]], 0 -// CHECK-LE-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP7]] to i8 +// CHECK-LE-NEXT: [[TMP7:%.*]] = load ppc_fp128, ptr @ld, align 16 +// CHECK-LE-NEXT: [[TMP8:%.*]] = bitcast ppc_fp128 [[TMP7]] to i128 +// CHECK-LE-NEXT: [[TMP9:%.*]] = trunc i128 [[TMP8]] to i64 +// CHECK-LE-NEXT: [[TMP10:%.*]] = icmp slt i64 [[TMP9]], 0 +// CHECK-LE-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TMP10]] to i8 // CHECK-LE-NEXT: store i8 [[FROMBOOL2]], ptr @b, align 1 -// CHECK-LE-NEXT: [[TMP8:%.*]] = icmp slt i64 trunc (i128 bitcast (ppc_fp128 0xM3FF00000000000000000000000000000 to i128) to i64), 0 -// CHECK-LE-NEXT: [[FROMBOOL3:%.*]] = zext i1 [[TMP8]] to i8 -// CHECK-LE-NEXT: store i8 [[FROMBOOL3]], ptr @b, align 1 -// CHECK-LE-NEXT: [[TMP9:%.*]] = load ppc_fp128, ptr @ld, align 16 -// CHECK-LE-NEXT: [[TMP10:%.*]] = bitcast ppc_fp128 [[TMP9]] to i128 -// CHECK-LE-NEXT: [[TMP11:%.*]] = trunc i128 [[TMP10]] to i64 -// CHECK-LE-NEXT: [[TMP12:%.*]] = icmp slt i64 [[TMP11]], 0 -// CHECK-LE-NEXT: [[FROMBOOL4:%.*]] = zext i1 [[TMP12]] to i8 -// CHECK-LE-NEXT: store i8 [[FROMBOOL4]], ptr @b, align 1 // CHECK-LE-NEXT: ret void // void test_signbit() diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index 37b63cf4f6b328..c359eba4e3d16c 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -fexperimental-new-constant-interpreter -verify %s // Math stuff @@ -204,6 +205,53 @@ char isfpclass_snan_1 [!__builtin_isfpclass(__builtin_nans(""), 0x0002) ? 1 : char isfpclass_snan_2 [__builtin_isfpclass(__builtin_nansl(""), 0x0207) ? 1 : -1]; // ~fcFinite char isfpclass_snan_3 [!__builtin_isfpclass(__builtin_nans(""), 0x01F8) ? 1 : -1]; // fcFinite +__extension__ _Static_assert( + !__builtin_signbit(1.0) && __builtin_signbit(-1.0) && !__builtin_signbit(0.0) && __builtin_signbit(-0.0) && + !__builtin_signbitf(1.0f) && __builtin_signbitf(-1.0f) && !__builtin_signbitf(0.0f) && __builtin_signbitf(-0.0f) && + !__builtin_signbitl(1.0L) && __builtin_signbitf(-1.0L) && !__builtin_signbitf(0.0L) && __builtin_signbitf(-0.0L) && + !__builtin_signbit(1.0f) && __builtin_signbit(-1.0f) && !__builtin_signbit(0.0f) && __builtin_signbit(-0.0f) && + !__builtin_signbit(1.0L) && __builtin_signbit(-1.0L) && !__builtin_signbit(0.0L) && __builtin_signbit(-0.0L) && +#if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__) + !__builtin_signbit(1.0q) && __builtin_signbit(-1.0q) && !__builtin_signbit(0.0q) && __builtin_signbit(-0.0q) && +#endif + 1, "" +); + +#define LESS(X, Y) \ + !__builtin_isgreater(X, Y) && __builtin_isgreater(Y, X) && \ + !__builtin_isgreaterequal(X, Y) && __builtin_isgreaterequal(Y, X) && \ + __builtin_isless(X, Y) && !__builtin_isless(Y, X) && \ + __builtin_islessequal(X, Y) && !__builtin_islessequal(Y, X) && \ + __builtin_islessgreater(X, Y) && __builtin_islessgreater(Y, X) && \ + !__builtin_isunordered(X, Y) && !__builtin_isunordered(Y, X) +#define EQUAL(X, Y) \ + !__builtin_isgreater(X, Y) && !__builtin_isgreater(Y, X) && \ + __builtin_isgreaterequal(X, Y) && __builtin_isgreaterequal(Y, X) && \ + !__builtin_isless(X, Y) && !__builtin_isless(Y, X) && \ + __builtin_islessequal(X, Y) && __builtin_islessequal(Y, X) && \ + !__builtin_islessgreater(X, Y) && !__builtin_islessgreater(Y, X) && \ + !__builtin_isunordered(X, Y) && !__builtin_isunordered(Y, X) +#define UNORDERED(X, Y) \ + !__builtin_isgreater(X, Y) && !__builtin_isgreater(Y, X) && \ + !__builtin_isgreaterequal(X, Y) && !__builtin_isgreaterequal(Y, X) && \ + !__builtin_isless(X, Y) && !__builtin_isless(Y, X) && \ + !__builtin_islessequal(X, Y) && !__builtin_islessequal(Y, X) && \ + !__builtin_islessgreater(X, Y) && !__builtin_islessgreater(Y, X) && \ + __builtin_isunordered(X, Y) && __builtin_isunordered(Y, X) + +__extension__ _Static_assert( + LESS(0.0, 1.0) && EQUAL(1.0, 1.0) && EQUAL(0.0, -0.0) && + UNORDERED(__builtin_nan(""), 1.0) && UNORDERED(__builtin_nan(""), __builtin_inf()) && LESS(0.0, __builtin_inf()) && + LESS(0.0f, 1.0f) && EQUAL(1.0f, 1.0f) && EQUAL(0.0f, -0.0f) && + UNORDERED(__builtin_nanf(""), 1.0f) && UNORDERED(__builtin_nanf(""), __builtin_inff()) && LESS(0.0f, __builtin_inff()) && + LESS(0.0L, 1.0L) && EQUAL(1.0L, 1.0L) && EQUAL(0.0L, -0.0L) && + UNORDERED(__builtin_nanl(""), 1.0L) && UNORDERED(__builtin_nanl(""), __builtin_infl()) && LESS(0.0L, __builtin_infl()) && +#if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__) + LESS(0.0q, 1.0q) && EQUAL(1.0q, 1.0q) && EQUAL(0.0q, -0.0q) && +#endif + 1, "" +); + //double g19 = __builtin_powi(2.0, 4); //float g20 = __builtin_powif(2.0f, 4); //long double g21 = __builtin_powil(2.0L, 4);