https://github.com/MitalAshok updated https://github.com/llvm/llvm-project/pull/94118
>From ed1c00ee4474a626965290f2d16aaaf0f4519ec9 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Sat, 1 Jun 2024 17:45:21 +0100 Subject: [PATCH 1/5] constexpr __builtin_signbit --- clang/include/clang/Basic/Builtins.td | 8 +++++--- clang/lib/AST/ExprConstant.cpp | 8 ++++++++ clang/lib/AST/Interp/InterpBuiltin.cpp | 15 +++++++++++++++ clang/test/Sema/constant-builtins-2.c | 13 +++++++++++++ 4 files changed, 41 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 11982af3fa609b..f784711bc04dc1 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -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/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index f1aa19e4409e15..b4de743c4d95bf 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12650,6 +12650,14 @@ 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_issignaling: { APFloat Val(0.0); return EvaluateFloat(E->getArg(0), Val, Info) && diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 00206d09c113d9..4ca92e66b29129 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -430,6 +430,15 @@ 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<Floating>(); + + pushInteger(S, Arg.isNegative(), 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, @@ -1214,6 +1223,12 @@ 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_isfpclass: if (!interp__builtin_isfpclass(S, OpPC, Frame, F, Call)) return false; diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index a60a1f16a45874..fca4ac2a26898f 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,18 @@ 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, "" +); + //double g19 = __builtin_powi(2.0, 4); //float g20 = __builtin_powif(2.0f, 4); //long double g21 = __builtin_powil(2.0L, 4); >From f08f0c4e6866fba98507a6ba7e817f586b92994f Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Sat, 1 Jun 2024 19:24:24 +0100 Subject: [PATCH 2/5] constexpr __builtin_is{less|greater|...|unordered} --- clang/include/clang/Basic/Builtins.td | 12 ++--- clang/lib/AST/ExprConstant.cpp | 59 +++++++++++++++++++++ clang/lib/AST/Interp/InterpBuiltin.cpp | 72 ++++++++++++++++++++++++++ clang/test/Sema/constant-builtins-2.c | 35 +++++++++++++ 4 files changed, 172 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index f784711bc04dc1..7b335e43f8c0ee 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(...)"; } diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index b4de743c4d95bf..cf715857f13707 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12658,6 +12658,65 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, 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; + + APFloat::cmpResult Cmp = LHS.compare(RHS); + bool FunctionResult; + if (BuiltinOp == Builtin::BI__builtin_isunordered || + Cmp == APFloat::cmpResult::cmpUnordered) { + FunctionResult = BuiltinOp == Builtin::BI__builtin_isunordered && + Cmp == APFloat::cmpResult::cmpUnordered; + } else { + int CmpStrong; + switch (Cmp) { + case APFloat::cmpResult::cmpEqual: + CmpStrong = 0; + break; + case APFloat::cmpResult::cmpLessThan: + CmpStrong = -1; + break; + case APFloat::cmpResult::cmpGreaterThan: + CmpStrong = 1; + break; + default: + llvm_unreachable("Unchecked cmpResult enum"); + } + + switch (BuiltinOp) { + case Builtin::BI__builtin_isgreater: + FunctionResult = CmpStrong > 0; + break; + case Builtin::BI__builtin_isgreaterequal: + FunctionResult = CmpStrong >= 0; + break; + case Builtin::BI__builtin_isless: + FunctionResult = CmpStrong < 0; + break; + case Builtin::BI__builtin_islessequal: + FunctionResult = CmpStrong <= 0; + break; + case Builtin::BI__builtin_islessgreater: + FunctionResult = CmpStrong != 0; + break; + default: + llvm_unreachable("Unexpected builtin ID: Should be a floating point " + "comparison function"); + } + } + + return Success(FunctionResult ? 1 : 0, E); + } + case Builtin::BI__builtin_issignaling: { APFloat Val(0.0); return EvaluateFloat(E->getArg(0), Val, Info) && diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 4ca92e66b29129..69e2960269c480 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -439,6 +439,69 @@ static bool interp__builtin_signbit(InterpState &S, CodePtr OpPC, 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<Floating>(); + const Floating &LHS = S.Stk.peek<Floating>(align(2u * primSize(PT_Float))); + unsigned ID = F->getBuiltinID(); + assert(ID == Builtin::BI__builtin_isgreater || + ID == Builtin::BI__builtin_isgreaterequal || + ID == Builtin::BI__builtin_isless || + ID == Builtin::BI__builtin_islessequal || + ID == Builtin::BI__builtin_islessgreater || + ID == Builtin::BI__builtin_isunordered); + + ComparisonCategoryResult Cmp = LHS.compare(RHS); + bool FunctionResult; + if (ID == Builtin::BI__builtin_isunordered || + Cmp == ComparisonCategoryResult::Unordered) { + FunctionResult = ID == Builtin::BI__builtin_isunordered && + Cmp == ComparisonCategoryResult::Unordered; + } else { + int CmpStrong; + switch (Cmp) { + case ComparisonCategoryResult::Equal: + case ComparisonCategoryResult::Equivalent: + CmpStrong = 0; + break; + case ComparisonCategoryResult::Less: + CmpStrong = -1; + break; + case ComparisonCategoryResult::Greater: + CmpStrong = 1; + break; + default: + llvm_unreachable("Unchecked ComparisonCategoryResult enum"); + } + + switch (ID) { + case Builtin::BI__builtin_isgreater: + FunctionResult = CmpStrong > 0; + break; + case Builtin::BI__builtin_isgreaterequal: + FunctionResult = CmpStrong >= 0; + break; + case Builtin::BI__builtin_isless: + FunctionResult = CmpStrong < 0; + break; + case Builtin::BI__builtin_islessequal: + FunctionResult = CmpStrong <= 0; + break; + case Builtin::BI__builtin_islessgreater: + FunctionResult = CmpStrong != 0; + break; + default: + llvm_unreachable("Unexpected builtin ID: Should be a floating point " + "comparison function"); + } + } + + pushInteger(S, FunctionResult, 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, @@ -1229,6 +1292,15 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, 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/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c index fca4ac2a26898f..59afdf056ae9ff 100644 --- a/clang/test/Sema/constant-builtins-2.c +++ b/clang/test/Sema/constant-builtins-2.c @@ -217,6 +217,41 @@ __extension__ _Static_assert( 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); >From 0d9de42fd70f34a42bc859932c24ff5b1627a26c Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Sat, 1 Jun 2024 20:15:43 +0100 Subject: [PATCH 3/5] Regenerate clang/test/Analysis/builtin_signbit.cpp Three of those lines are constant folded now --- clang/test/Analysis/builtin_signbit.cpp | 126 ++++++++++-------------- 1 file changed, 53 insertions(+), 73 deletions(-) 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() >From 49e9468723c74a4ddb44c6b5ed94d1223e670036 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Tue, 4 Jun 2024 18:16:47 +0100 Subject: [PATCH 4/5] Add release note --- clang/docs/ReleaseNotes.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 0c700d23257bf7..7fbd10b3180476 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -323,6 +323,10 @@ Non-comprehensive list of changes in this release - Builtins ``__builtin_shufflevector()`` and ``__builtin_convertvector()`` may now be used within constant expressions. +- 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 ------------------ - ``-fsanitize=implicit-bitfield-conversion`` checks implicit truncation and >From afc47030356bb9ad4ad3e2be720699157a3eb806 Mon Sep 17 00:00:00 2001 From: Mital Ashok <mi...@mitalashok.co.uk> Date: Tue, 4 Jun 2024 19:09:27 +0100 Subject: [PATCH 5/5] Simplifiy comparison function logic --- clang/lib/AST/ExprConstant.cpp | 71 +++++++++--------------- clang/lib/AST/Interp/InterpBuiltin.cpp | 77 +++++++++----------------- 2 files changed, 51 insertions(+), 97 deletions(-) diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index cf715857f13707..7fca3f43ed9938 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -12670,51 +12670,32 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, !EvaluateFloat(E->getArg(1), RHS, Info)) return false; - APFloat::cmpResult Cmp = LHS.compare(RHS); - bool FunctionResult; - if (BuiltinOp == Builtin::BI__builtin_isunordered || - Cmp == APFloat::cmpResult::cmpUnordered) { - FunctionResult = BuiltinOp == Builtin::BI__builtin_isunordered && - Cmp == APFloat::cmpResult::cmpUnordered; - } else { - int CmpStrong; - switch (Cmp) { - case APFloat::cmpResult::cmpEqual: - CmpStrong = 0; - break; - case APFloat::cmpResult::cmpLessThan: - CmpStrong = -1; - break; - case APFloat::cmpResult::cmpGreaterThan: - CmpStrong = 1; - break; - default: - llvm_unreachable("Unchecked cmpResult enum"); - } - - switch (BuiltinOp) { - case Builtin::BI__builtin_isgreater: - FunctionResult = CmpStrong > 0; - break; - case Builtin::BI__builtin_isgreaterequal: - FunctionResult = CmpStrong >= 0; - break; - case Builtin::BI__builtin_isless: - FunctionResult = CmpStrong < 0; - break; - case Builtin::BI__builtin_islessequal: - FunctionResult = CmpStrong <= 0; - break; - case Builtin::BI__builtin_islessgreater: - FunctionResult = CmpStrong != 0; - break; - default: - llvm_unreachable("Unexpected builtin ID: Should be a floating point " - "comparison function"); - } - } - - return Success(FunctionResult ? 1 : 0, E); + 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: { diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp index 69e2960269c480..9acbd8204275d6 100644 --- a/clang/lib/AST/Interp/InterpBuiltin.cpp +++ b/clang/lib/AST/Interp/InterpBuiltin.cpp @@ -446,59 +446,32 @@ static bool interp_floating_comparison(InterpState &S, CodePtr OpPC, const Floating &RHS = S.Stk.peek<Floating>(); const Floating &LHS = S.Stk.peek<Floating>(align(2u * primSize(PT_Float))); unsigned ID = F->getBuiltinID(); - assert(ID == Builtin::BI__builtin_isgreater || - ID == Builtin::BI__builtin_isgreaterequal || - ID == Builtin::BI__builtin_isless || - ID == Builtin::BI__builtin_islessequal || - ID == Builtin::BI__builtin_islessgreater || - ID == Builtin::BI__builtin_isunordered); - - ComparisonCategoryResult Cmp = LHS.compare(RHS); - bool FunctionResult; - if (ID == Builtin::BI__builtin_isunordered || - Cmp == ComparisonCategoryResult::Unordered) { - FunctionResult = ID == Builtin::BI__builtin_isunordered && - Cmp == ComparisonCategoryResult::Unordered; - } else { - int CmpStrong; - switch (Cmp) { - case ComparisonCategoryResult::Equal: - case ComparisonCategoryResult::Equivalent: - CmpStrong = 0; - break; - case ComparisonCategoryResult::Less: - CmpStrong = -1; - break; - case ComparisonCategoryResult::Greater: - CmpStrong = 1; - break; - default: - llvm_unreachable("Unchecked ComparisonCategoryResult enum"); - } - - switch (ID) { - case Builtin::BI__builtin_isgreater: - FunctionResult = CmpStrong > 0; - break; - case Builtin::BI__builtin_isgreaterequal: - FunctionResult = CmpStrong >= 0; - break; - case Builtin::BI__builtin_isless: - FunctionResult = CmpStrong < 0; - break; - case Builtin::BI__builtin_islessequal: - FunctionResult = CmpStrong <= 0; - break; - case Builtin::BI__builtin_islessgreater: - FunctionResult = CmpStrong != 0; - break; - default: - llvm_unreachable("Unexpected builtin ID: Should be a floating point " - "comparison function"); - } - } - pushInteger(S, FunctionResult, Call->getType()); + 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; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits