https://github.com/Serosh-commits updated https://github.com/llvm/llvm-project/pull/194327
>From 3bb020cd4fc050fb27fb043bc113beb002176a02 Mon Sep 17 00:00:00 2001 From: Serosh-commits <[email protected]> Date: Mon, 27 Apr 2026 01:55:47 +0530 Subject: [PATCH 1/6] [Clang] Add constexpr eval for cmath builtins Enable compile-time evaluation of math builtins like ceil, floor, fmod, fma, frexp, ilogb, nextafter, scalbn, etc. in both the AST evaluator and the bytecode interpreter. --- clang/include/clang/Basic/Builtins.td | 77 ++- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 469 ++++++++++++++++++ clang/lib/AST/ExprConstant.cpp | 327 ++++++++++++ .../test/SemaCXX/constexpr-cmath-builtins.cpp | 187 +++++++ 4 files changed, 1033 insertions(+), 27 deletions(-) create mode 100644 clang/test/SemaCXX/constexpr-cmath-builtins.cpp diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index b8bbc544595e2..c0e37ab77220e 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -133,7 +133,7 @@ def CbrtF128 : Builtin { def CeilF16F128 : Builtin, F16F128MathTemplate { let Spellings = ["__builtin_ceil"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr]; let Prototype = "T(T)"; } @@ -187,19 +187,19 @@ def Expm1F128 : Builtin { def FdimF128 : Builtin { let Spellings = ["__builtin_fdimf128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "__float128(__float128, __float128)"; } def FloorF16F128 : Builtin, F16F128MathTemplate { let Spellings = ["__builtin_floor"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr]; let Prototype = "T(T)"; } def FmaF16F128 : Builtin, F16F128MathTemplate { let Spellings = ["__builtin_fma"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "T(T, T, T)"; } @@ -259,13 +259,13 @@ def FabsF128 : Builtin { def FmodF16F128 : F16F128MathTemplate, Builtin { let Spellings = ["__builtin_fmod"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "T(T, T)"; } def FrexpF16F128 : F16F128MathTemplate, Builtin { let Spellings = ["__builtin_frexp"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "T(T, int*)"; } @@ -295,13 +295,13 @@ def InfF16 : Builtin { def LdexpF16F128 : F16F128MathTemplate, Builtin { let Spellings = ["__builtin_ldexp"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "T(T, int)"; } def ModfF128 : Builtin { let Spellings = ["__builtin_modff128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Constexpr]; let Prototype = "__float128(__float128, __float128*)"; } @@ -347,7 +347,7 @@ def HypotF128 : Builtin { def ILogbF128 : Builtin { let Spellings = ["__builtin_ilogbf128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "int(__float128)"; } @@ -359,13 +359,13 @@ def LgammaF128 : Builtin { def LLrintF128 : Builtin { let Spellings = ["__builtin_llrintf128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "long long int(__float128)"; } def LLroundF128 : Builtin { let Spellings = ["__builtin_llroundf128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "long long int(__float128)"; } @@ -401,55 +401,55 @@ def LogF16F128 : Builtin, F16F128MathTemplate { def LrintF128 : Builtin { let Spellings = ["__builtin_lrintf128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "long int(__float128)"; } def LroundF128 : Builtin { let Spellings = ["__builtin_lroundf128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "long int(__float128)"; } -def NearbyintF128 : Builtin { - let Spellings = ["__builtin_nearbyintf128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const]; - let Prototype = "__float128(__float128)"; +def NearbyintF16F128 : Builtin, F16F128MathTemplate { + let Spellings = ["__builtin_nearbyint"]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr]; + let Prototype = "T(T)"; } def NextafterF128 : Builtin { let Spellings = ["__builtin_nextafterf128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "__float128(__float128, __float128)"; } def NexttowardF128 : Builtin { let Spellings = ["__builtin_nexttowardf128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "__float128(__float128, __float128)"; } def RemainderF128 : Builtin { let Spellings = ["__builtin_remainderf128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "__float128(__float128, __float128)"; } def RemquoF128 : Builtin { let Spellings = ["__builtin_remquof128"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Constexpr]; let Prototype = "__float128(__float128, __float128, int*)"; } def RintF16F128 : Builtin, F16F128MathTemplate { let Spellings = ["__builtin_rint"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr]; let Prototype = "T(T)"; } def RoundF16F128 : Builtin, F16F128MathTemplate { let Spellings = ["__builtin_round"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr]; let Prototype = "T(T)"; } @@ -462,14 +462,14 @@ def RoundevenF16F128 : Builtin, F16F128MathTemplate { def ScanlblnF128 : Builtin { let Spellings = ["__builtin_scalblnf128"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow, - ConstIgnoringErrnoAndExceptions]; + ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "__float128(__float128, long int)"; } def ScanlbnF128 : Builtin { let Spellings = ["__builtin_scalbnf128"]; let Attributes = [FunctionWithBuiltinPrefix, NoThrow, - ConstIgnoringErrnoAndExceptions]; + ConstIgnoringErrnoAndExceptions, Constexpr]; let Prototype = "__float128(__float128, int)"; } @@ -517,7 +517,7 @@ def TgammaF128 : Builtin { def TruncF16F128 : Builtin, F16F128MathTemplate { let Spellings = ["__builtin_trunc"]; - let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const]; + let Attributes = [FunctionWithBuiltinPrefix, NoThrow, Const, Constexpr]; let Prototype = "T(T)"; } @@ -3796,6 +3796,7 @@ def Fmod : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "T(T, T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Frexp : FPMathTemplate, LibBuiltin<"math.h"> { @@ -3803,6 +3804,7 @@ def Frexp : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow]; let Prototype = "T(T, int*)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Sincos : FPMathTemplate, GNULibBuiltin<"math.h"> { @@ -3823,6 +3825,7 @@ def Ldexp : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "T(T, int)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Modf : FPMathTemplate, LibBuiltin<"math.h"> { @@ -3830,6 +3833,7 @@ def Modf : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow]; let Prototype = "T(T, T*)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Nan : FPMathTemplate, LibBuiltin<"math.h"> { @@ -3901,6 +3905,7 @@ def Ceil : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, Const]; let Prototype = "T(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Cos : FPMathTemplate, LibBuiltin<"math.h"> { @@ -3965,6 +3970,7 @@ def Fdim : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "T(T, T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Floor : FPMathTemplate, LibBuiltin<"math.h"> { @@ -3972,6 +3978,7 @@ def Floor : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, Const]; let Prototype = "T(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Fma : FPMathTemplate, LibBuiltin<"math.h"> { @@ -3979,6 +3986,7 @@ def Fma : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "T(T, T, T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Fmax : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4025,6 +4033,7 @@ def Ilogb : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "int(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Lgamma : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4039,6 +4048,7 @@ def Llrint : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "long long int(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Llround : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4046,6 +4056,7 @@ def Llround : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "long long int(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Log : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4088,6 +4099,7 @@ def Lrint : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "long int(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Lround : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4095,13 +4107,15 @@ def Lround : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "long int(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Nearbyint : FPMathTemplate, LibBuiltin<"math.h"> { let Spellings = ["nearbyint"]; - let Attributes = [NoThrow, Const]; + let Attributes = [NoThrow, Const, Constexpr]; let Prototype = "T(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Nextafter : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4109,6 +4123,7 @@ def Nextafter : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "T(T, T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Nexttoward : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4116,6 +4131,7 @@ def Nexttoward : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "T(T, long double)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Remainder : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4123,6 +4139,7 @@ def Remainder : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "T(T, T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Remquo : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4130,6 +4147,7 @@ def Remquo : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow]; let Prototype = "T(T, T, int*)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Rint : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4137,6 +4155,7 @@ def Rint : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringExceptions]; let Prototype = "T(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Round : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4144,6 +4163,7 @@ def Round : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, Const]; let Prototype = "T(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def RoundEven : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4158,6 +4178,7 @@ def Scalbln : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "T(T, long int)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Scalbn : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4165,6 +4186,7 @@ def Scalbn : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, ConstIgnoringErrnoAndExceptions]; let Prototype = "T(T, int)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Sin : FPMathTemplate, LibBuiltin<"math.h"> { @@ -4214,6 +4236,7 @@ def Trunc : FPMathTemplate, LibBuiltin<"math.h"> { let Attributes = [NoThrow, Const]; let Prototype = "T(T)"; let AddBuiltinPrefixedAlias = 1; + let OnlyBuiltinPrefixedAliasIsConstexpr = 1; } def Cabs : FPMathTemplate, LibBuiltin<"complex.h"> { diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index e7b3ef6ce1510..bce535cc6f0f5 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -707,6 +707,348 @@ static inline Floating abs(InterpState &S, const Floating &In) { return Output; } +static bool interp__builtin_ceil(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Floating &Val = S.Stk.pop<Floating>(); + Floating Result = S.allocFloat(Val.getSemantics()); + APFloat F = Val.getAPFloat(); + unsigned BuiltinOp = Call->getBuiltinCallee(); + + llvm::RoundingMode RM; + switch (BuiltinOp) { + case Builtin::BI__builtin_ceil: + case Builtin::BI__builtin_ceilf: + case Builtin::BI__builtin_ceill: + case Builtin::BI__builtin_ceilf16: + case Builtin::BI__builtin_ceilf128: + RM = llvm::RoundingMode::TowardPositive; + break; + case Builtin::BI__builtin_floor: + case Builtin::BI__builtin_floorf: + case Builtin::BI__builtin_floorl: + case Builtin::BI__builtin_floorf16: + case Builtin::BI__builtin_floorf128: + RM = llvm::RoundingMode::TowardNegative; + break; + case Builtin::BI__builtin_trunc: + case Builtin::BI__builtin_truncf: + case Builtin::BI__builtin_truncl: + case Builtin::BI__builtin_truncf16: + case Builtin::BI__builtin_truncf128: + RM = llvm::RoundingMode::TowardZero; + break; + default: + llvm_unreachable("invalid builtin ID"); + } + + F.roundToIntegral(RM); + Result.copy(F); + S.Stk.push<Floating>(Result); + return true; +} + +static bool interp__builtin_fdim(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Floating &RHS = S.Stk.pop<Floating>(); + const Floating &LHS = S.Stk.pop<Floating>(); + APFloat L = LHS.getAPFloat(); + APFloat R = RHS.getAPFloat(); + APFloat Result(L.getSemantics()); + + if (L.compare(R) == APFloat::cmpGreaterThan) { + L.subtract(R, APFloat::rmNearestTiesToEven); + Result = L; + } else if (L.isNaN() || R.isNaN()) { + L.add(R, APFloat::rmNearestTiesToEven); + Result = L; + } else { + Result = APFloat::getZero(L.getSemantics()); + } + + Floating F = S.allocFloat(Result.getSemantics()); + F.copy(Result); + S.Stk.push<Floating>(F); + return true; +} + +static bool interp__builtin_fma(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Floating &Z = S.Stk.pop<Floating>(); + const Floating &Y = S.Stk.pop<Floating>(); + const Floating &X = S.Stk.pop<Floating>(); + APFloat Result = X.getAPFloat(); + + const FPOptions FPO = Call->getFPFeaturesInEffect(S.getLangOpts()); + llvm::RoundingMode RM = FPO.getRoundingMode(); + if (RM == llvm::RoundingMode::Dynamic) + RM = llvm::RoundingMode::NearestTiesToEven; + + Result.fusedMultiplyAdd(Y.getAPFloat(), Z.getAPFloat(), RM); + Floating F = S.allocFloat(Result.getSemantics()); + F.copy(Result); + S.Stk.push<Floating>(F); + return true; +} + +static bool interp__builtin_frexp(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Pointer &Ptr = S.Stk.pop<Pointer>(); + const Floating &Val = S.Stk.pop<Floating>(); + + int Exp = 0; + const FPOptions FPO = Call->getFPFeaturesInEffect(S.getLangOpts()); + llvm::RoundingMode RM = FPO.getRoundingMode(); + if (RM == llvm::RoundingMode::Dynamic) + RM = llvm::RoundingMode::NearestTiesToEven; + + APFloat F = frexp(Val.getAPFloat(), Exp, RM); + + if (!Ptr.isDummy()) { + QualType ExpType = Call->getArg(1)->getType()->getPointeeType(); + PrimType ExpT = *S.getContext().classify(ExpType); + assignInteger(S, Ptr, ExpT, APSInt::get(Exp)); + Ptr.initialize(); + } + + Floating Result = S.allocFloat(F.getSemantics()); + Result.copy(F); + S.Stk.push<Floating>(Result); + return true; +} + +static bool interp__builtin_modf(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Pointer &Ptr = S.Stk.pop<Pointer>(); + const Floating &Val = S.Stk.pop<Floating>(); + + APFloat Integral = Val.getAPFloat(); + Integral.roundToIntegral(APFloat::rmTowardZero); + + if (!Ptr.isDummy()) { + Ptr.deref<Floating>().copy(Integral); + Ptr.initialize(); + } + + if (Val.getAPFloat().isInfinity()) { + Floating Fraction = S.allocFloat(Val.getAPFloat().getSemantics()); + Fraction.copy(APFloat::getZero(Val.getAPFloat().getSemantics(), Val.getAPFloat().isNegative())); + S.Stk.push<Floating>(Fraction); + return true; + } + + APFloat Fraction = Val.getAPFloat(); + Fraction.subtract(Integral, APFloat::rmNearestTiesToEven); + + Floating Result = S.allocFloat(Fraction.getSemantics()); + Result.copy(Fraction); + S.Stk.push<Floating>(Result); + return true; +} + +static bool interp__builtin_fmod(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Floating &RHS = S.Stk.pop<Floating>(); + const Floating &LHS = S.Stk.pop<Floating>(); + APFloat L = LHS.getAPFloat(); + unsigned BuiltinOp = Call->getBuiltinCallee(); + + if (BuiltinOp == Builtin::BI__builtin_remainder || + BuiltinOp == Builtin::BI__builtin_remainderf || + BuiltinOp == Builtin::BI__builtin_remainderl || + BuiltinOp == Builtin::BI__builtin_remainderf128) + L.remainder(RHS.getAPFloat()); + else + L.mod(RHS.getAPFloat()); + + Floating F = S.allocFloat(L.getSemantics()); + F.copy(L); + S.Stk.push<Floating>(F); + return true; +} + +static bool interp__builtin_nextafter(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Floating &RHS = S.Stk.pop<Floating>(); + const Floating &LHS = S.Stk.pop<Floating>(); + APFloat L = LHS.getAPFloat(); + APFloat R = RHS.getAPFloat(); + + if (L.isNaN()) { + S.Stk.push<Floating>(LHS); + return true; + } + + if (R.isNaN()) { + bool LoseInfo = false; + L = R; + L.convert(LHS.getSemantics(), APFloat::rmNearestTiesToEven, &LoseInfo); + Floating Result = S.allocFloat(L.getSemantics()); + Result.copy(L); + S.Stk.push<Floating>(Result); + return true; + } + + APFloat LCopy = L; + bool LoseInfo = false; + LCopy.convert(R.getSemantics(), APFloat::rmNearestTiesToEven, &LoseInfo); + APFloat::cmpResult Res = LCopy.compare(R); + + if (Res != APFloat::cmpEqual) + L.next(Res == APFloat::cmpGreaterThan); + + Floating Result = S.allocFloat(L.getSemantics()); + Result.copy(L); + S.Stk.push<Floating>(Result); + return true; +} + +static bool interp__builtin_scalbn(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + PrimType ExpT = *S.getContext().classify(Call->getArg(1)->getType()); + APSInt Exp = popToAPSInt(S.Stk, ExpT); + const Floating &Val = S.Stk.pop<Floating>(); + + const FPOptions FPO = Call->getFPFeaturesInEffect(S.getLangOpts()); + llvm::RoundingMode RM = FPO.getRoundingMode(); + if (RM == llvm::RoundingMode::Dynamic) + RM = llvm::RoundingMode::NearestTiesToEven; + + Floating Result = S.allocFloat(Val.getSemantics()); + Result.copy(scalbn(Val.getAPFloat(), (int)Exp.getExtValue(), RM)); + S.Stk.push<Floating>(Result); + return true; +} + +static bool interp__builtin_ilogb(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Floating &Val = S.Stk.pop<Floating>(); + if (Val.getAPFloat().isZero() || Val.getAPFloat().isNaN()) { + pushInteger(S, -2147483648LL, Call->getType()); + return true; + } + pushInteger(S, ilogb(Val.getAPFloat()), Call->getType()); + return true; +} + +static bool interp__builtin_remquo(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Pointer &Ptr = S.Stk.pop<Pointer>(); + const Floating &RHS = S.Stk.pop<Floating>(); + const Floating &LHS = S.Stk.pop<Floating>(); + + APFloat Q = LHS.getAPFloat(); + if (Q.divide(RHS.getAPFloat(), APFloat::rmNearestTiesToEven) & APFloat::opInvalidOp) + Q = APFloat::getZero(Q.getSemantics()); + else + Q.roundToIntegral(APFloat::rmNearestTiesToEven); + + if (!Ptr.isDummy()) { + QualType QuoType = Call->getArg(2)->getType()->getPointeeType(); + APSInt QuoInt(S.getASTContext().getTypeSize(QuoType), false); + bool IsExact = false; + Q.convertToInteger(QuoInt, APFloat::rmTowardZero, &IsExact); + + PrimType QuoT = *S.getContext().classify(QuoType); + assignInteger(S, Ptr, QuoT, QuoInt); + Ptr.initialize(); + } + + APFloat R = LHS.getAPFloat(); + R.remainder(RHS.getAPFloat()); + Floating Result = S.allocFloat(R.getSemantics()); + Result.copy(R); + S.Stk.push<Floating>(Result); + return true; +} + +static bool interp__builtin_round(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Floating &Val = S.Stk.pop<Floating>(); + Floating Result = S.allocFloat(Val.getSemantics()); + APFloat F = Val.getAPFloat(); + + F.roundToIntegral(llvm::RoundingMode::NearestTiesToAway); + Result.copy(F); + S.Stk.push<Floating>(Result); + return true; +} + +static bool interp__builtin_lrint(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Floating &Val = S.Stk.pop<Floating>(); + APFloat F = Val.getAPFloat(); + unsigned BuiltinOp = Call->getBuiltinCallee(); + + llvm::RoundingMode RM; + switch (BuiltinOp) { + case Builtin::BI__builtin_lround: + case Builtin::BI__builtin_lroundf: + case Builtin::BI__builtin_lroundl: + case Builtin::BI__builtin_lroundf128: + case Builtin::BI__builtin_llround: + case Builtin::BI__builtin_llroundf: + case Builtin::BI__builtin_llroundl: + case Builtin::BI__builtin_llroundf128: + RM = llvm::RoundingMode::NearestTiesToAway; + break; + default: { + const FPOptions FPO = Call->getFPFeaturesInEffect(S.getLangOpts()); + RM = FPO.getRoundingMode(); + if (RM == llvm::RoundingMode::Dynamic) + RM = llvm::RoundingMode::NearestTiesToEven; + break; + } + } + + F.roundToIntegral(RM); + + APSInt IntVal(S.getASTContext().getTypeSize(Call->getType()), + Call->getType()->isUnsignedIntegerOrEnumerationType()); + bool IsExact = false; + APFloat::opStatus Status = F.convertToInteger(IntVal, RM, &IsExact); + + if (Status & APFloat::opInvalidOp) { + if (S.diagnosing()) { + auto Loc = S.Current->getSource(OpPC); + S.CCEDiag(Loc, diag::note_constexpr_float_arithmetic) + << (F.isNaN() ? 1 : 0); + } + } + + pushInteger(S, IntVal, Call->getType()); + return true; +} + +static bool interp__builtin_nearbyint(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call) { + const Floating &Val = S.Stk.pop<Floating>(); + Floating Result = S.allocFloat(Val.getSemantics()); + APFloat F = Val.getAPFloat(); + + const FPOptions FPO = Call->getFPFeaturesInEffect(S.getLangOpts()); + llvm::RoundingMode RM = FPO.getRoundingMode(); + if (RM == llvm::RoundingMode::Dynamic) + RM = llvm::RoundingMode::NearestTiesToEven; + + F.roundToIntegral(RM); + Result.copy(F); + S.Stk.push<Floating>(Result); + return true; +} + // The C standard says "fabs raises no floating-point exceptions, // even if x is a signaling NaN. The returned value is independent of // the current rounding direction mode." Therefore constant folding can @@ -4300,6 +4642,133 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_issubnormal: return interp__builtin_issubnormal(S, OpPC, Frame, Call); + case Builtin::BI__builtin_nearbyint: + case Builtin::BI__builtin_nearbyintf: + case Builtin::BI__builtin_nearbyintl: + case Builtin::BI__builtin_nearbyintf16: + case Builtin::BI__builtin_nearbyintf128: + case Builtin::BI__builtin_rint: + case Builtin::BI__builtin_rintf: + case Builtin::BI__builtin_rintl: + case Builtin::BI__builtin_rintf16: + case Builtin::BI__builtin_rintf128: + return interp__builtin_nearbyint(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_lrint: + case Builtin::BI__builtin_lrintf: + case Builtin::BI__builtin_lrintl: + case Builtin::BI__builtin_lrintf128: + case Builtin::BI__builtin_llrint: + case Builtin::BI__builtin_llrintf: + case Builtin::BI__builtin_llrintl: + case Builtin::BI__builtin_llrintf128: + case Builtin::BI__builtin_lround: + case Builtin::BI__builtin_lroundf: + case Builtin::BI__builtin_lroundl: + case Builtin::BI__builtin_lroundf128: + case Builtin::BI__builtin_llround: + case Builtin::BI__builtin_llroundf: + case Builtin::BI__builtin_llroundl: + case Builtin::BI__builtin_llroundf128: + return interp__builtin_lrint(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_ceil: + case Builtin::BI__builtin_ceilf: + case Builtin::BI__builtin_ceill: + case Builtin::BI__builtin_ceilf16: + case Builtin::BI__builtin_ceilf128: + case Builtin::BI__builtin_floor: + case Builtin::BI__builtin_floorf: + case Builtin::BI__builtin_floorl: + case Builtin::BI__builtin_floorf16: + case Builtin::BI__builtin_floorf128: + case Builtin::BI__builtin_trunc: + case Builtin::BI__builtin_truncf: + case Builtin::BI__builtin_truncl: + case Builtin::BI__builtin_truncf16: + case Builtin::BI__builtin_truncf128: + return interp__builtin_ceil(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_fdim: + case Builtin::BI__builtin_fdimf: + case Builtin::BI__builtin_fdiml: + case Builtin::BI__builtin_fdimf128: + return interp__builtin_fdim(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_frexp: + case Builtin::BI__builtin_frexpf: + case Builtin::BI__builtin_frexpl: + case Builtin::BI__builtin_frexpf16: + case Builtin::BI__builtin_frexpf128: + return interp__builtin_frexp(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_modf: + case Builtin::BI__builtin_modff: + case Builtin::BI__builtin_modfl: + case Builtin::BI__builtin_modff128: + return interp__builtin_modf(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_fma: + case Builtin::BI__builtin_fmaf: + case Builtin::BI__builtin_fmal: + case Builtin::BI__builtin_fmaf16: + case Builtin::BI__builtin_fmaf128: + return interp__builtin_fma(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_fmod: + case Builtin::BI__builtin_fmodf: + case Builtin::BI__builtin_fmodl: + case Builtin::BI__builtin_fmodf16: + case Builtin::BI__builtin_fmodf128: + case Builtin::BI__builtin_remainder: + case Builtin::BI__builtin_remainderf: + case Builtin::BI__builtin_remainderf128: + return interp__builtin_fmod(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_nextafter: + case Builtin::BI__builtin_nextafterf: + case Builtin::BI__builtin_nextafterl: + case Builtin::BI__builtin_nextafterf128: + case Builtin::BI__builtin_nexttoward: + case Builtin::BI__builtin_nexttowardf: + case Builtin::BI__builtin_nexttowardl: + case Builtin::BI__builtin_nexttowardf128: + return interp__builtin_nextafter(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_scalbn: + case Builtin::BI__builtin_scalbnf: + case Builtin::BI__builtin_scalbnl: + case Builtin::BI__builtin_scalbnf128: + case Builtin::BI__builtin_scalbln: + case Builtin::BI__builtin_scalblnf: + case Builtin::BI__builtin_scalblnl: + case Builtin::BI__builtin_scalblnf128: + case Builtin::BI__builtin_ldexp: + case Builtin::BI__builtin_ldexpf: + case Builtin::BI__builtin_ldexpl: + case Builtin::BI__builtin_ldexpf16: + case Builtin::BI__builtin_ldexpf128: + return interp__builtin_scalbn(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_ilogb: + case Builtin::BI__builtin_ilogbf: + case Builtin::BI__builtin_ilogbl: + case Builtin::BI__builtin_ilogbf128: + return interp__builtin_ilogb(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_remquo: + case Builtin::BI__builtin_remquof: + case Builtin::BI__builtin_remquol: + case Builtin::BI__builtin_remquof128: + return interp__builtin_remquo(S, OpPC, Frame, Call); + + case Builtin::BI__builtin_round: + case Builtin::BI__builtin_roundf: + case Builtin::BI__builtin_roundl: + case Builtin::BI__builtin_roundf16: + case Builtin::BI__builtin_roundf128: + return interp__builtin_round(S, OpPC, Frame, Call); + case Builtin::BI__builtin_iszero: return interp__builtin_iszero(S, OpPC, Frame, Call); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 4f45fa728c605..9b89f7997b133 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -16275,6 +16275,57 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, }; switch (BuiltinOp) { + case Builtin::BI__builtin_lrint: + case Builtin::BI__builtin_lrintf: + case Builtin::BI__builtin_lrintl: + case Builtin::BI__builtin_lrintf128: + case Builtin::BI__builtin_llrint: + case Builtin::BI__builtin_llrintf: + case Builtin::BI__builtin_llrintl: + case Builtin::BI__builtin_llrintf128: + case Builtin::BI__builtin_lround: + case Builtin::BI__builtin_lroundf: + case Builtin::BI__builtin_lroundl: + case Builtin::BI__builtin_lroundf128: + case Builtin::BI__builtin_llround: + case Builtin::BI__builtin_llroundf: + case Builtin::BI__builtin_llroundl: + case Builtin::BI__builtin_llroundf128: { + APFloat FloatVal(0.0); + if (!EvaluateFloat(E->getArg(0), FloatVal, Info)) + return false; + + llvm::RoundingMode RM; + switch (BuiltinOp) { + case Builtin::BI__builtin_lround: + case Builtin::BI__builtin_lroundf: + case Builtin::BI__builtin_lroundl: + case Builtin::BI__builtin_lroundf128: + case Builtin::BI__builtin_llround: + case Builtin::BI__builtin_llroundf: + case Builtin::BI__builtin_llroundl: + case Builtin::BI__builtin_llroundf128: + RM = llvm::RoundingMode::NearestTiesToAway; + break; + default: + RM = getActiveRoundingMode(Info, E); + break; + } + + FloatVal.roundToIntegral(RM); + + APSInt IntVal(Info.Ctx.getTypeSize(E->getType()), + E->getType()->isUnsignedIntegerOrEnumerationType()); + bool IsExact = false; + APFloat::opStatus Status = FloatVal.convertToInteger(IntVal, RM, &IsExact); + + if (Status & APFloat::opInvalidOp) + Info.CCEDiag(E, diag::note_constexpr_float_arithmetic) + << (FloatVal.isNaN() ? 1 : 0); + + return Success(IntVal, E); + } + default: return false; @@ -16744,6 +16795,19 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return Success(Val.popcount() % 2, E); } + case Builtin::BI__builtin_ilogb: + case Builtin::BI__builtin_ilogbf: + case Builtin::BI__builtin_ilogbl: + case Builtin::BI__builtin_ilogbf128: { + APFloat FloatVal(0.0); + if (!EvaluateFloat(E->getArg(0), FloatVal, Info)) + return false; + + if (FloatVal.isZero() || FloatVal.isNaN()) + return Success(-2147483648LL, E); + return Success(ilogb(FloatVal), E); + } + case Builtin::BI__builtin_abs: case Builtin::BI__builtin_labs: case Builtin::BI__builtin_llabs: { @@ -19634,6 +19698,269 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { return true; } + case Builtin::BI__builtin_nearbyint: + case Builtin::BI__builtin_nearbyintf: + case Builtin::BI__builtin_nearbyintl: + case Builtin::BI__builtin_nearbyintf16: + case Builtin::BI__builtin_nearbyintf128: + case Builtin::BI__builtin_rint: + case Builtin::BI__builtin_rintf: + case Builtin::BI__builtin_rintl: + case Builtin::BI__builtin_rintf16: + case Builtin::BI__builtin_rintf128: { + if (!EvaluateFloat(E->getArg(0), Result, Info)) + return false; + llvm::RoundingMode RM = getActiveRoundingMode(getEvalInfo(), E); + Result.roundToIntegral(RM); + return true; + } + + case Builtin::BI__builtin_round: + case Builtin::BI__builtin_roundf: + case Builtin::BI__builtin_roundl: + case Builtin::BI__builtin_roundf16: + case Builtin::BI__builtin_roundf128: { + if (!EvaluateFloat(E->getArg(0), Result, Info)) + return false; + Result.roundToIntegral(llvm::RoundingMode::NearestTiesToAway); + return true; + } + + case Builtin::BI__builtin_ceil: + case Builtin::BI__builtin_ceilf: + case Builtin::BI__builtin_ceill: + case Builtin::BI__builtin_ceilf16: + case Builtin::BI__builtin_ceilf128: + case Builtin::BI__builtin_floor: + case Builtin::BI__builtin_floorf: + case Builtin::BI__builtin_floorl: + case Builtin::BI__builtin_floorf16: + case Builtin::BI__builtin_floorf128: + case Builtin::BI__builtin_trunc: + case Builtin::BI__builtin_truncf: + case Builtin::BI__builtin_truncl: + case Builtin::BI__builtin_truncf16: + case Builtin::BI__builtin_truncf128: { + if (!EvaluateFloat(E->getArg(0), Result, Info)) + return false; + llvm::RoundingMode RM; + switch (E->getBuiltinCallee()) { + case Builtin::BI__builtin_ceil: + case Builtin::BI__builtin_ceilf: + case Builtin::BI__builtin_ceill: + case Builtin::BI__builtin_ceilf16: + case Builtin::BI__builtin_ceilf128: + RM = llvm::RoundingMode::TowardPositive; + break; + case Builtin::BI__builtin_floor: + case Builtin::BI__builtin_floorf: + case Builtin::BI__builtin_floorl: + case Builtin::BI__builtin_floorf16: + case Builtin::BI__builtin_floorf128: + RM = llvm::RoundingMode::TowardNegative; + break; + default: + RM = llvm::RoundingMode::TowardZero; + break; + } + Result.roundToIntegral(RM); + return true; + } + + case Builtin::BI__builtin_fdim: + case Builtin::BI__builtin_fdimf: + case Builtin::BI__builtin_fdiml: + case Builtin::BI__builtin_fdimf128: { + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + if (Result.compare(RHS) == APFloat::cmpGreaterThan) { + Result.subtract(RHS, APFloat::rmNearestTiesToEven); + } else if (Result.isNaN() || RHS.isNaN()) { + Result.add(RHS, APFloat::rmNearestTiesToEven); + } else { + Result = APFloat::getZero(Result.getSemantics()); + } + return true; + } + + case Builtin::BI__builtin_fma: + case Builtin::BI__builtin_fmaf: + case Builtin::BI__builtin_fmal: + case Builtin::BI__builtin_fmaf16: + case Builtin::BI__builtin_fmaf128: { + APFloat RHS(0.), Third(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info) || + !EvaluateFloat(E->getArg(2), Third, Info)) + return false; + + llvm::RoundingMode RM = getActiveRoundingMode(getEvalInfo(), E); + Result.fusedMultiplyAdd(RHS, Third, RM); + return true; + } + + case Builtin::BI__builtin_fmod: + case Builtin::BI__builtin_fmodf: + case Builtin::BI__builtin_fmodl: + case Builtin::BI__builtin_fmodf16: + case Builtin::BI__builtin_fmodf128: { + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + Result.mod(RHS); + return true; + } + + case Builtin::BI__builtin_remainder: + case Builtin::BI__builtin_remainderf: + case Builtin::BI__builtin_remainderl: + case Builtin::BI__builtin_remainderf128: { + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + Result.remainder(RHS); + return true; + } + + case Builtin::BI__builtin_nextafter: + case Builtin::BI__builtin_nextafterf: + case Builtin::BI__builtin_nextafterl: + case Builtin::BI__builtin_nextafterf128: + case Builtin::BI__builtin_nexttoward: + case Builtin::BI__builtin_nexttowardf: + case Builtin::BI__builtin_nexttowardl: + case Builtin::BI__builtin_nexttowardf128: { + APFloat RHS(0.); + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info)) + return false; + + if (Result.isNaN()) + return true; + + if (RHS.isNaN()) { + bool LoseInfo = false; + Result = RHS; + Result.convert(Info.Ctx.getFloatTypeSemantics(E->getType()), + APFloat::rmNearestTiesToEven, &LoseInfo); + return true; + } + + APFloat ResultCopy = Result; + bool LoseInfo = false; + ResultCopy.convert(RHS.getSemantics(), APFloat::rmNearestTiesToEven, &LoseInfo); + APFloat::cmpResult Res = ResultCopy.compare(RHS); + + if (Res == APFloat::cmpEqual) + return true; + + Result.next(Res == APFloat::cmpGreaterThan); + return true; + } + + case Builtin::BI__builtin_scalbn: + case Builtin::BI__builtin_scalbnf: + case Builtin::BI__builtin_scalbnl: + case Builtin::BI__builtin_scalbnf128: + case Builtin::BI__builtin_scalbln: + case Builtin::BI__builtin_scalblnf: + case Builtin::BI__builtin_scalblnl: + case Builtin::BI__builtin_scalblnf128: + case Builtin::BI__builtin_ldexp: + case Builtin::BI__builtin_ldexpf: + case Builtin::BI__builtin_ldexpl: + case Builtin::BI__builtin_ldexpf16: + case Builtin::BI__builtin_ldexpf128: { + APSInt Exp; + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateInteger(E->getArg(1), Exp, Info)) + return false; + + llvm::RoundingMode RM = getActiveRoundingMode(getEvalInfo(), E); + Result = scalbn(Result, Exp.getExtValue(), RM); + return true; + } + + case Builtin::BI__builtin_frexp: + case Builtin::BI__builtin_frexpf: + case Builtin::BI__builtin_frexpl: + case Builtin::BI__builtin_frexpf16: + case Builtin::BI__builtin_frexpf128: { + LValue ExpLVal; + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluatePointer(E->getArg(1), ExpLVal, Info)) + return false; + + int Exp = 0; + llvm::RoundingMode RM = getActiveRoundingMode(getEvalInfo(), E); + Result = frexp(Result, Exp, RM); + + QualType PointeeType = E->getArg(1)->getType()->getPointeeType(); + APValue APV{APSInt(Info.Ctx.getTypeSize(PointeeType), false)}; + APV.getInt() = Exp; + if (!handleAssignment(Info, E, ExpLVal, PointeeType, APV)) + return false; + return true; + } + + case Builtin::BI__builtin_modf: + case Builtin::BI__builtin_modff: + case Builtin::BI__builtin_modfl: + case Builtin::BI__builtin_modff128: { + LValue IptrLVal; + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluatePointer(E->getArg(1), IptrLVal, Info)) + return false; + + APFloat Integral = Result; + Integral.roundToIntegral(APFloat::rmTowardZero); + + QualType PointeeType = E->getArg(1)->getType()->getPointeeType(); + APValue APV{Integral}; + if (!handleAssignment(Info, E, IptrLVal, PointeeType, APV)) + return false; + + if (Result.isInfinity()) { + Result = APFloat::getZero(Result.getSemantics(), Result.isNegative()); + } else { + Result.subtract(Integral, APFloat::rmNearestTiesToEven); + } + return true; + } + + case Builtin::BI__builtin_remquo: + case Builtin::BI__builtin_remquof: + case Builtin::BI__builtin_remquol: + case Builtin::BI__builtin_remquof128: { + APFloat RHS(0.); + LValue QuoLVal; + if (!EvaluateFloat(E->getArg(0), Result, Info) || + !EvaluateFloat(E->getArg(1), RHS, Info) || + !EvaluatePointer(E->getArg(2), QuoLVal, Info)) + return false; + + APFloat Q = Result; + if (Q.divide(RHS, APFloat::rmNearestTiesToEven) & APFloat::opInvalidOp) + Q = APFloat::getZero(Q.getSemantics()); + else + Q.roundToIntegral(APFloat::rmNearestTiesToEven); + + APSInt QuoInt(Info.Ctx.getTypeSize(E->getArg(2)->getType()->getPointeeType()), false); + bool IsExact = false; + Q.convertToInteger(QuoInt, APFloat::rmTowardZero, &IsExact); + + APValue APV{QuoInt}; + if (!handleAssignment(Info, E, QuoLVal, E->getArg(2)->getType()->getPointeeType(), APV)) + return false; + + Result.remainder(RHS); + return true; + } + case Builtin::BI__builtin_elementwise_fma: { if (!E->getArg(0)->isPRValue() || !E->getArg(1)->isPRValue() || !E->getArg(2)->isPRValue()) { diff --git a/clang/test/SemaCXX/constexpr-cmath-builtins.cpp b/clang/test/SemaCXX/constexpr-cmath-builtins.cpp new file mode 100644 index 0000000000000..368617b27b863 --- /dev/null +++ b/clang/test/SemaCXX/constexpr-cmath-builtins.cpp @@ -0,0 +1,187 @@ +// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify -std=c++20 %s +// RUN: %clang_cc1 -verify -std=c++20 %s + +// expected-no-diagnostics + +static_assert(__builtin_nearbyint(1.1) == 1.0); +static_assert(__builtin_nearbyint(1.9) == 2.0); +static_assert(__builtin_nearbyint(-1.1) == -1.0); +static_assert(__builtin_nearbyint(-1.9) == -2.0); + +static_assert(__builtin_nearbyintf(1.1f) == 1.0f); +static_assert(__builtin_nearbyintl(1.1l) == 1.0l); + +// Test ties to even (default rounding mode) +static_assert(__builtin_nearbyint(1.5) == 2.0); +static_assert(__builtin_nearbyint(2.5) == 2.0); + +// rint tests +static_assert(__builtin_rint(1.1) == 1.0); +static_assert(__builtin_rint(1.9) == 2.0); +static_assert(__builtin_rintf(1.1f) == 1.0f); +static_assert(__builtin_rintl(1.1l) == 1.0l); +static_assert(__builtin_rintf16(1.1f16) == 1.0f16); +static_assert(__builtin_rintf128(1.1) == 1.0); + +// lrint tests +static_assert(__builtin_lrint(1.1) == 1); +static_assert(__builtin_lrint(1.9) == 2); +static_assert(__builtin_lrintf(1.1f) == 1); +static_assert(__builtin_lrintl(1.1l) == 1); +static_assert(__builtin_lrintf128(1.1) == 1); + +// llrint tests +static_assert(__builtin_llrint(1.1) == 1LL); +static_assert(__builtin_llrint(1.9) == 2LL); +static_assert(__builtin_llrintf(1.1f) == 1LL); +static_assert(__builtin_llrintl(1.1l) == 1LL); +static_assert(__builtin_llrintf128(1.1) == 1LL); + +// round tests +static_assert(__builtin_round(1.1) == 1.0); +static_assert(__builtin_round(1.5) == 2.0); +static_assert(__builtin_round(1.9) == 2.0); +static_assert(__builtin_round(-1.5) == -2.0); + +// lround tests +static_assert(__builtin_lround(1.1) == 1); +static_assert(__builtin_lround(1.5) == 2); +static_assert(__builtin_lround(-1.5) == -2); + +// llround tests +static_assert(__builtin_llround(1.1) == 1LL); +static_assert(__builtin_llround(1.5) == 2LL); +static_assert(__builtin_llround(-1.5) == -2LL); + +// ceil tests +static_assert(__builtin_ceil(1.1) == 2.0); +static_assert(__builtin_ceil(-1.1) == -1.0); +static_assert(__builtin_ceilf(1.1f) == 2.0f); + +// floor tests +static_assert(__builtin_floor(1.1) == 1.0); +static_assert(__builtin_floor(-1.1) == -2.0); +static_assert(__builtin_floorf(1.1f) == 1.0f); + +// trunc tests +static_assert(__builtin_trunc(1.1) == 1.0); +static_assert(__builtin_trunc(-1.1) == -1.0); +static_assert(__builtin_truncf(1.1f) == 1.0f); + +// fdim tests +static_assert(__builtin_fdim(3.0, 1.0) == 2.0); +static_assert(__builtin_fdim(1.0, 3.0) == 0.0); +static_assert(__builtin_fdimf(3.0f, 1.0f) == 2.0f); + +// fma tests +static_assert(__builtin_fma(2.0, 3.0, 4.0) == 10.0); +static_assert(__builtin_fmaf(2.0f, 3.0f, 4.0f) == 10.0f); + +// fmod tests +static_assert(__builtin_fmod(5.5, 3.0) == 2.5); +static_assert(__builtin_fmodf(5.5f, 3.0f) == 2.5f); + +// remainder tests +static_assert(__builtin_remainder(5.5, 3.0) == -0.5); +static_assert(__builtin_remainderf(5.5f, 3.0f) == -0.5f); + +// nextafter tests +static_assert(__builtin_nextafter(1.0, 2.0) > 1.0); +static_assert(__builtin_nextafter(1.0, 0.0) < 1.0); +static_assert(__builtin_nextafter(1.0, 1.0) == 1.0); +static_assert(__builtin_nextafter(0.0, 1.0) > 0.0); +static_assert(__builtin_nextafter(0.0, -1.0) < 0.0); + +// nexttoward tests +static_assert(__builtin_nexttoward(1.0, 2.0L) > 1.0); +static_assert(__builtin_nexttoward(1.0, 1.0L) == 1.0); + +// scalbn tests +static_assert(__builtin_scalbn(1.0, 2) == 4.0); +static_assert(__builtin_scalbnf(1.0f, -1) == 0.5f); + +// scalbln tests +static_assert(__builtin_scalbln(1.0, 2L) == 4.0); + +// ldexp tests +static_assert(__builtin_ldexp(1.0, 3) == 8.0); + +// ilogb tests +static_assert(__builtin_ilogb(1.0) == 0); +static_assert(__builtin_ilogb(2.0) == 1); +static_assert(__builtin_ilogb(0.5) == -1); +static_assert(__builtin_ilogbf(8.0f) == 3); + +// remquo tests +constexpr double test_remquo(double x, double y) { + int quo = 0; + double rem = __builtin_remquo(x, y, &quo); + return rem; +} +static_assert(test_remquo(10.0, 3.0) == 1.0); + +constexpr int test_remquo_quo(double x, double y) { + int quo = 0; + __builtin_remquo(x, y, &quo); + return quo; +} +static_assert(test_remquo_quo(10.0, 3.0) == 3); +static_assert(test_remquo_quo(10.0, -3.0) == -3); + +// frexp tests +constexpr double test_frexp_val(double x) { + int exp = 0; + return __builtin_frexp(x, &exp); +} +static_assert(test_frexp_val(8.0) == 0.5); + +constexpr int test_frexp_exp(double x) { + int exp = 0; + __builtin_frexp(x, &exp); + return exp; +} +static_assert(test_frexp_exp(8.0) == 4); + +// modf tests +constexpr double test_modf_val(double x) { + double iptr = 0; + return __builtin_modf(x, &iptr); +} +static_assert(test_modf_val(3.14) > 0.139 && test_modf_val(3.14) < 0.141); + +constexpr double test_modf_iptr(double x) { + double iptr = 0; + __builtin_modf(x, &iptr); + return iptr; +} +static_assert(test_modf_iptr(3.14) == 3.0); + +// ilogb special values +static_assert(__builtin_ilogb(0.0) == -2147483648); +static_assert(__builtin_ilogb(__builtin_nan("")) == -2147483648); +static_assert(__builtin_ilogb(__builtin_inf()) == 2147483647); + +// modf special values +constexpr double test_modf_inf_val() { + double iptr = 0; + return __builtin_modf(__builtin_inf(), &iptr); +} +static_assert(test_modf_inf_val() == 0.0); + +constexpr double test_modf_inf_iptr() { + double iptr = 0; + __builtin_modf(__builtin_inf(), &iptr); + return iptr; +} +static_assert(__builtin_isinf(test_modf_inf_iptr())); + +// fdim special values +static_assert(__builtin_fdim(__builtin_inf(), __builtin_inf()) == 0.0); + +// remquo special values (returns NaN for y=0) +constexpr bool test_remquo_nan() { + int quo = 0; + double rem = __builtin_remquo(1.0, 0.0, &quo); + return __builtin_isnan(rem); +} +static_assert(test_remquo_nan()); >From 42524697f1cc329384f8a2f426dc1e45ea5c11e4 Mon Sep 17 00:00:00 2001 From: Serosh-commits <[email protected]> Date: Mon, 27 Apr 2026 18:33:39 +0530 Subject: [PATCH 2/6] address feedback --- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 93 ++++++++++-------------- clang/lib/AST/ExprConstant.cpp | 2 - 2 files changed, 37 insertions(+), 58 deletions(-) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index bce535cc6f0f5..535ebc4914917 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -709,11 +709,10 @@ static inline Floating abs(InterpState &S, const Floating &In) { static bool interp__builtin_ceil(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, - const CallExpr *Call) { + const CallExpr *Call, unsigned BuiltinOp) { const Floating &Val = S.Stk.pop<Floating>(); Floating Result = S.allocFloat(Val.getSemantics()); APFloat F = Val.getAPFloat(); - unsigned BuiltinOp = Call->getBuiltinCallee(); llvm::RoundingMode RM; switch (BuiltinOp) { @@ -781,10 +780,7 @@ static bool interp__builtin_fma(InterpState &S, CodePtr OpPC, const Floating &X = S.Stk.pop<Floating>(); APFloat Result = X.getAPFloat(); - const FPOptions FPO = Call->getFPFeaturesInEffect(S.getLangOpts()); - llvm::RoundingMode RM = FPO.getRoundingMode(); - if (RM == llvm::RoundingMode::Dynamic) - RM = llvm::RoundingMode::NearestTiesToEven; + llvm::RoundingMode RM = getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); Result.fusedMultiplyAdd(Y.getAPFloat(), Z.getAPFloat(), RM); Floating F = S.allocFloat(Result.getSemantics()); @@ -800,17 +796,14 @@ static bool interp__builtin_frexp(InterpState &S, CodePtr OpPC, const Floating &Val = S.Stk.pop<Floating>(); int Exp = 0; - const FPOptions FPO = Call->getFPFeaturesInEffect(S.getLangOpts()); - llvm::RoundingMode RM = FPO.getRoundingMode(); - if (RM == llvm::RoundingMode::Dynamic) - RM = llvm::RoundingMode::NearestTiesToEven; + llvm::RoundingMode RM = getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); APFloat F = frexp(Val.getAPFloat(), Exp, RM); if (!Ptr.isDummy()) { QualType ExpType = Call->getArg(1)->getType()->getPointeeType(); PrimType ExpT = *S.getContext().classify(ExpType); - assignInteger(S, Ptr, ExpT, APSInt::get(Exp)); + assignIntegral(S, Ptr, ExpT, APSInt::get(Exp)); Ptr.initialize(); } @@ -825,8 +818,9 @@ static bool interp__builtin_modf(InterpState &S, CodePtr OpPC, const CallExpr *Call) { const Pointer &Ptr = S.Stk.pop<Pointer>(); const Floating &Val = S.Stk.pop<Floating>(); + const APFloat &F = Val.getAPFloat(); - APFloat Integral = Val.getAPFloat(); + APFloat Integral = F; Integral.roundToIntegral(APFloat::rmTowardZero); if (!Ptr.isDummy()) { @@ -834,14 +828,14 @@ static bool interp__builtin_modf(InterpState &S, CodePtr OpPC, Ptr.initialize(); } - if (Val.getAPFloat().isInfinity()) { - Floating Fraction = S.allocFloat(Val.getAPFloat().getSemantics()); - Fraction.copy(APFloat::getZero(Val.getAPFloat().getSemantics(), Val.getAPFloat().isNegative())); + if (F.isInfinity()) { + Floating Fraction = S.allocFloat(F.getSemantics()); + Fraction.copy(APFloat::getZero(F.getSemantics(), F.isNegative())); S.Stk.push<Floating>(Fraction); return true; } - APFloat Fraction = Val.getAPFloat(); + APFloat Fraction = F; Fraction.subtract(Integral, APFloat::rmNearestTiesToEven); Floating Result = S.allocFloat(Fraction.getSemantics()); @@ -852,22 +846,23 @@ static bool interp__builtin_modf(InterpState &S, CodePtr OpPC, static bool interp__builtin_fmod(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, - const CallExpr *Call) { + const CallExpr *Call, unsigned BuiltinOp) { const Floating &RHS = S.Stk.pop<Floating>(); const Floating &LHS = S.Stk.pop<Floating>(); - APFloat L = LHS.getAPFloat(); - unsigned BuiltinOp = Call->getBuiltinCallee(); + const APFloat &L = LHS.getAPFloat(); + const APFloat &R = RHS.getAPFloat(); + APFloat ResF = L; if (BuiltinOp == Builtin::BI__builtin_remainder || BuiltinOp == Builtin::BI__builtin_remainderf || BuiltinOp == Builtin::BI__builtin_remainderl || BuiltinOp == Builtin::BI__builtin_remainderf128) - L.remainder(RHS.getAPFloat()); + ResF.remainder(R); else - L.mod(RHS.getAPFloat()); + ResF.mod(R); - Floating F = S.allocFloat(L.getSemantics()); - F.copy(L); + Floating F = S.allocFloat(ResF.getSemantics()); + F.copy(ResF); S.Stk.push<Floating>(F); return true; } @@ -877,8 +872,8 @@ static bool interp__builtin_nextafter(InterpState &S, CodePtr OpPC, const CallExpr *Call) { const Floating &RHS = S.Stk.pop<Floating>(); const Floating &LHS = S.Stk.pop<Floating>(); - APFloat L = LHS.getAPFloat(); - APFloat R = RHS.getAPFloat(); + const APFloat &L = LHS.getAPFloat(); + const APFloat &R = RHS.getAPFloat(); if (L.isNaN()) { S.Stk.push<Floating>(LHS); @@ -887,10 +882,10 @@ static bool interp__builtin_nextafter(InterpState &S, CodePtr OpPC, if (R.isNaN()) { bool LoseInfo = false; - L = R; - L.convert(LHS.getSemantics(), APFloat::rmNearestTiesToEven, &LoseInfo); - Floating Result = S.allocFloat(L.getSemantics()); - Result.copy(L); + APFloat NaN = R; + NaN.convert(L.getSemantics(), APFloat::rmNearestTiesToEven, &LoseInfo); + Floating Result = S.allocFloat(NaN.getSemantics()); + Result.copy(NaN); S.Stk.push<Floating>(Result); return true; } @@ -900,11 +895,12 @@ static bool interp__builtin_nextafter(InterpState &S, CodePtr OpPC, LCopy.convert(R.getSemantics(), APFloat::rmNearestTiesToEven, &LoseInfo); APFloat::cmpResult Res = LCopy.compare(R); + APFloat Next = L; if (Res != APFloat::cmpEqual) - L.next(Res == APFloat::cmpGreaterThan); + Next.next(Res == APFloat::cmpGreaterThan); - Floating Result = S.allocFloat(L.getSemantics()); - Result.copy(L); + Floating Result = S.allocFloat(Next.getSemantics()); + Result.copy(Next); S.Stk.push<Floating>(Result); return true; } @@ -916,10 +912,7 @@ static bool interp__builtin_scalbn(InterpState &S, CodePtr OpPC, APSInt Exp = popToAPSInt(S.Stk, ExpT); const Floating &Val = S.Stk.pop<Floating>(); - const FPOptions FPO = Call->getFPFeaturesInEffect(S.getLangOpts()); - llvm::RoundingMode RM = FPO.getRoundingMode(); - if (RM == llvm::RoundingMode::Dynamic) - RM = llvm::RoundingMode::NearestTiesToEven; + llvm::RoundingMode RM = getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); Floating Result = S.allocFloat(Val.getSemantics()); Result.copy(scalbn(Val.getAPFloat(), (int)Exp.getExtValue(), RM)); @@ -931,10 +924,6 @@ static bool interp__builtin_ilogb(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { const Floating &Val = S.Stk.pop<Floating>(); - if (Val.getAPFloat().isZero() || Val.getAPFloat().isNaN()) { - pushInteger(S, -2147483648LL, Call->getType()); - return true; - } pushInteger(S, ilogb(Val.getAPFloat()), Call->getType()); return true; } @@ -959,7 +948,7 @@ static bool interp__builtin_remquo(InterpState &S, CodePtr OpPC, Q.convertToInteger(QuoInt, APFloat::rmTowardZero, &IsExact); PrimType QuoT = *S.getContext().classify(QuoType); - assignInteger(S, Ptr, QuoT, QuoInt); + assignIntegral(S, Ptr, QuoT, QuoInt); Ptr.initialize(); } @@ -986,10 +975,9 @@ static bool interp__builtin_round(InterpState &S, CodePtr OpPC, static bool interp__builtin_lrint(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, - const CallExpr *Call) { + const CallExpr *Call, unsigned BuiltinOp) { const Floating &Val = S.Stk.pop<Floating>(); APFloat F = Val.getAPFloat(); - unsigned BuiltinOp = Call->getBuiltinCallee(); llvm::RoundingMode RM; switch (BuiltinOp) { @@ -1003,14 +991,10 @@ static bool interp__builtin_lrint(InterpState &S, CodePtr OpPC, case Builtin::BI__builtin_llroundf128: RM = llvm::RoundingMode::NearestTiesToAway; break; - default: { - const FPOptions FPO = Call->getFPFeaturesInEffect(S.getLangOpts()); - RM = FPO.getRoundingMode(); - if (RM == llvm::RoundingMode::Dynamic) - RM = llvm::RoundingMode::NearestTiesToEven; + default: + RM = getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); break; } - } F.roundToIntegral(RM); @@ -1038,10 +1022,7 @@ static bool interp__builtin_nearbyint(InterpState &S, CodePtr OpPC, Floating Result = S.allocFloat(Val.getSemantics()); APFloat F = Val.getAPFloat(); - const FPOptions FPO = Call->getFPFeaturesInEffect(S.getLangOpts()); - llvm::RoundingMode RM = FPO.getRoundingMode(); - if (RM == llvm::RoundingMode::Dynamic) - RM = llvm::RoundingMode::NearestTiesToEven; + llvm::RoundingMode RM = getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); F.roundToIntegral(RM); Result.copy(F); @@ -4670,7 +4651,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_llroundf: case Builtin::BI__builtin_llroundl: case Builtin::BI__builtin_llroundf128: - return interp__builtin_lrint(S, OpPC, Frame, Call); + return interp__builtin_lrint(S, OpPC, Frame, Call, ID); case Builtin::BI__builtin_ceil: case Builtin::BI__builtin_ceilf: @@ -4687,7 +4668,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_truncl: case Builtin::BI__builtin_truncf16: case Builtin::BI__builtin_truncf128: - return interp__builtin_ceil(S, OpPC, Frame, Call); + return interp__builtin_ceil(S, OpPC, Frame, Call, ID); case Builtin::BI__builtin_fdim: case Builtin::BI__builtin_fdimf: @@ -4723,7 +4704,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_remainder: case Builtin::BI__builtin_remainderf: case Builtin::BI__builtin_remainderf128: - return interp__builtin_fmod(S, OpPC, Frame, Call); + return interp__builtin_fmod(S, OpPC, Frame, Call, ID); case Builtin::BI__builtin_nextafter: case Builtin::BI__builtin_nextafterf: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 9b89f7997b133..c1449cf33f002 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -16803,8 +16803,6 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, if (!EvaluateFloat(E->getArg(0), FloatVal, Info)) return false; - if (FloatVal.isZero() || FloatVal.isNaN()) - return Success(-2147483648LL, E); return Success(ilogb(FloatVal), E); } >From a8b9e7329d31c0904ccf4c4c2d5c6ea5e74fad16 Mon Sep 17 00:00:00 2001 From: Serosh-commits <[email protected]> Date: Mon, 27 Apr 2026 19:17:31 +0530 Subject: [PATCH 3/6] ci fixes --- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 56 ++++++++++++++----- clang/lib/AST/ExprConstant.cpp | 11 ++-- clang/test/CodeGen/logb_scalbn.c | 6 +- .../test/SemaCXX/constexpr-cmath-builtins.cpp | 6 +- 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 535ebc4914917..5967869bf227c 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -57,13 +57,29 @@ static APSInt popToAPSInt(InterpStack &Stk, PrimType T) { INT_TYPE_SWITCH(T, return Stk.pop<T>().toAPSInt()); } +static bool popToAPSInt(InterpStack &Stk, PrimType T, APSInt &Out) { + Out = popToAPSInt(Stk, T); + return true; +} + static APSInt popToAPSInt(InterpState &S, const Expr *E) { return popToAPSInt(S.Stk, *S.getContext().classify(E->getType())); } + +static bool popToAPSInt(InterpState &S, const Expr *E, APSInt &Out) { + Out = popToAPSInt(S, E); + return true; +} + static APSInt popToAPSInt(InterpState &S, QualType T) { return popToAPSInt(S.Stk, *S.getContext().classify(T)); } +static bool popToAPSInt(InterpState &S, QualType T, APSInt &Out) { + Out = popToAPSInt(S, T); + return true; +} + /// Check for common reasons a pointer can't be read from, which /// are usually not diagnosed in a builtin function. static bool isReadable(const Pointer &P) { @@ -141,6 +157,11 @@ static void assignInteger(InterpState &S, const Pointer &Dest, PrimType ValueT, } } +static void assignIntegral(InterpState &S, const Pointer &Dest, PrimType ValueT, + const APSInt &Value) { + assignInteger(S, Dest, ValueT, Value); +} + static QualType getElemType(const Pointer &P) { const Descriptor *Desc = P.getFieldDesc(); QualType T = Desc->getType(); @@ -708,8 +729,8 @@ static inline Floating abs(InterpState &S, const Floating &In) { } static bool interp__builtin_ceil(InterpState &S, CodePtr OpPC, - const InterpFrame *Frame, - const CallExpr *Call, unsigned BuiltinOp) { + const InterpFrame *Frame, const CallExpr *Call, + unsigned BuiltinOp) { const Floating &Val = S.Stk.pop<Floating>(); Floating Result = S.allocFloat(Val.getSemantics()); APFloat F = Val.getAPFloat(); @@ -780,7 +801,8 @@ static bool interp__builtin_fma(InterpState &S, CodePtr OpPC, const Floating &X = S.Stk.pop<Floating>(); APFloat Result = X.getAPFloat(); - llvm::RoundingMode RM = getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); + llvm::RoundingMode RM = + getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); Result.fusedMultiplyAdd(Y.getAPFloat(), Z.getAPFloat(), RM); Floating F = S.allocFloat(Result.getSemantics()); @@ -796,7 +818,8 @@ static bool interp__builtin_frexp(InterpState &S, CodePtr OpPC, const Floating &Val = S.Stk.pop<Floating>(); int Exp = 0; - llvm::RoundingMode RM = getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); + llvm::RoundingMode RM = + getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); APFloat F = frexp(Val.getAPFloat(), Exp, RM); @@ -845,8 +868,8 @@ static bool interp__builtin_modf(InterpState &S, CodePtr OpPC, } static bool interp__builtin_fmod(InterpState &S, CodePtr OpPC, - const InterpFrame *Frame, - const CallExpr *Call, unsigned BuiltinOp) { + const InterpFrame *Frame, const CallExpr *Call, + unsigned BuiltinOp) { const Floating &RHS = S.Stk.pop<Floating>(); const Floating &LHS = S.Stk.pop<Floating>(); const APFloat &L = LHS.getAPFloat(); @@ -909,10 +932,13 @@ static bool interp__builtin_scalbn(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call) { PrimType ExpT = *S.getContext().classify(Call->getArg(1)->getType()); - APSInt Exp = popToAPSInt(S.Stk, ExpT); + APSInt Exp; + if (!popToAPSInt(S.Stk, ExpT, Exp)) + return false; const Floating &Val = S.Stk.pop<Floating>(); - llvm::RoundingMode RM = getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); + llvm::RoundingMode RM = + getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); Floating Result = S.allocFloat(Val.getSemantics()); Result.copy(scalbn(Val.getAPFloat(), (int)Exp.getExtValue(), RM)); @@ -936,7 +962,8 @@ static bool interp__builtin_remquo(InterpState &S, CodePtr OpPC, const Floating &LHS = S.Stk.pop<Floating>(); APFloat Q = LHS.getAPFloat(); - if (Q.divide(RHS.getAPFloat(), APFloat::rmNearestTiesToEven) & APFloat::opInvalidOp) + if (Q.divide(RHS.getAPFloat(), APFloat::rmNearestTiesToEven) & + APFloat::opInvalidOp) Q = APFloat::getZero(Q.getSemantics()); else Q.roundToIntegral(APFloat::rmNearestTiesToEven); @@ -999,7 +1026,7 @@ static bool interp__builtin_lrint(InterpState &S, CodePtr OpPC, F.roundToIntegral(RM); APSInt IntVal(S.getASTContext().getTypeSize(Call->getType()), - Call->getType()->isUnsignedIntegerOrEnumerationType()); + Call->getType()->isUnsignedIntegerOrEnumerationType()); bool IsExact = false; APFloat::opStatus Status = F.convertToInteger(IntVal, RM, &IsExact); @@ -1022,7 +1049,8 @@ static bool interp__builtin_nearbyint(InterpState &S, CodePtr OpPC, Floating Result = S.allocFloat(Val.getSemantics()); APFloat F = Val.getAPFloat(); - llvm::RoundingMode RM = getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); + llvm::RoundingMode RM = + getRoundingMode(Call->getFPFeaturesInEffect(S.getLangOpts())); F.roundToIntegral(RM); Result.copy(F); @@ -4651,7 +4679,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_llroundf: case Builtin::BI__builtin_llroundl: case Builtin::BI__builtin_llroundf128: - return interp__builtin_lrint(S, OpPC, Frame, Call, ID); + return interp__builtin_lrint(S, OpPC, Frame, Call, BuiltinID); case Builtin::BI__builtin_ceil: case Builtin::BI__builtin_ceilf: @@ -4668,7 +4696,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_truncl: case Builtin::BI__builtin_truncf16: case Builtin::BI__builtin_truncf128: - return interp__builtin_ceil(S, OpPC, Frame, Call, ID); + return interp__builtin_ceil(S, OpPC, Frame, Call, BuiltinID); case Builtin::BI__builtin_fdim: case Builtin::BI__builtin_fdimf: @@ -4704,7 +4732,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_remainder: case Builtin::BI__builtin_remainderf: case Builtin::BI__builtin_remainderf128: - return interp__builtin_fmod(S, OpPC, Frame, Call, ID); + return interp__builtin_fmod(S, OpPC, Frame, Call, BuiltinID); case Builtin::BI__builtin_nextafter: case Builtin::BI__builtin_nextafterf: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index c1449cf33f002..1e333758a4eb2 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -16315,7 +16315,7 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, FloatVal.roundToIntegral(RM); APSInt IntVal(Info.Ctx.getTypeSize(E->getType()), - E->getType()->isUnsignedIntegerOrEnumerationType()); + E->getType()->isUnsignedIntegerOrEnumerationType()); bool IsExact = false; APFloat::opStatus Status = FloatVal.convertToInteger(IntVal, RM, &IsExact); @@ -19850,7 +19850,8 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { APFloat ResultCopy = Result; bool LoseInfo = false; - ResultCopy.convert(RHS.getSemantics(), APFloat::rmNearestTiesToEven, &LoseInfo); + ResultCopy.convert(RHS.getSemantics(), APFloat::rmNearestTiesToEven, + &LoseInfo); APFloat::cmpResult Res = ResultCopy.compare(RHS); if (Res == APFloat::cmpEqual) @@ -19947,12 +19948,14 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { else Q.roundToIntegral(APFloat::rmNearestTiesToEven); - APSInt QuoInt(Info.Ctx.getTypeSize(E->getArg(2)->getType()->getPointeeType()), false); + APSInt QuoInt( + Info.Ctx.getTypeSize(E->getArg(2)->getType()->getPointeeType()), false); bool IsExact = false; Q.convertToInteger(QuoInt, APFloat::rmTowardZero, &IsExact); APValue APV{QuoInt}; - if (!handleAssignment(Info, E, QuoLVal, E->getArg(2)->getType()->getPointeeType(), APV)) + if (!handleAssignment(Info, E, QuoLVal, + E->getArg(2)->getType()->getPointeeType(), APV)) return false; Result.remainder(RHS); diff --git a/clang/test/CodeGen/logb_scalbn.c b/clang/test/CodeGen/logb_scalbn.c index 52c52bcb292be..d4d58f5c773de 100644 --- a/clang/test/CodeGen/logb_scalbn.c +++ b/clang/test/CodeGen/logb_scalbn.c @@ -777,8 +777,7 @@ void test_logb_var(double a) { // IGNORE-NEXT: [[ENTRY:.*:]] // IGNORE-NEXT: [[D1:%.*]] = alloca float, align 4, addrspace(5) // IGNORE-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// IGNORE-NEXT: [[TMP0:%.*]] = call float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10) -// IGNORE-NEXT: store float [[TMP0]], ptr [[D1_ASCAST]], align 4 +// IGNORE-NEXT: store float 0x40D0B33340000000, ptr [[D1_ASCAST]], align 4 // IGNORE-NEXT: ret void // // STRICT-LABEL: define dso_local void @test_scalbnf( @@ -1358,8 +1357,7 @@ void test_scalbnf_var3(float a, int b) { // IGNORE-NEXT: [[ENTRY:.*:]] // IGNORE-NEXT: [[D1:%.*]] = alloca double, align 8, addrspace(5) // IGNORE-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// IGNORE-NEXT: [[TMP0:%.*]] = call double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10) -// IGNORE-NEXT: store double [[TMP0]], ptr [[D1_ASCAST]], align 8 +// IGNORE-NEXT: store double 1.761280e+04, ptr [[D1_ASCAST]], align 8 // IGNORE-NEXT: ret void // // STRICT-LABEL: define dso_local void @test_scalbn( diff --git a/clang/test/SemaCXX/constexpr-cmath-builtins.cpp b/clang/test/SemaCXX/constexpr-cmath-builtins.cpp index 368617b27b863..79f28d795e179 100644 --- a/clang/test/SemaCXX/constexpr-cmath-builtins.cpp +++ b/clang/test/SemaCXX/constexpr-cmath-builtins.cpp @@ -157,9 +157,9 @@ constexpr double test_modf_iptr(double x) { static_assert(test_modf_iptr(3.14) == 3.0); // ilogb special values -static_assert(__builtin_ilogb(0.0) == -2147483648); -static_assert(__builtin_ilogb(__builtin_nan("")) == -2147483648); -static_assert(__builtin_ilogb(__builtin_inf()) == 2147483647); +static_assert(__builtin_ilogb(0.) == -2147483647L); +static_assert(__builtin_ilogb(__builtin_nan("")) == -2147483648L); +static_assert(__builtin_ilogb(__builtin_inf()) == 2147483647L); // modf special values constexpr double test_modf_inf_val() { >From 9d4a22f66540c248f9e3a7b80d83f4169b0b92a5 Mon Sep 17 00:00:00 2001 From: Serosh-commits <[email protected]> Date: Wed, 29 Apr 2026 02:58:46 +0530 Subject: [PATCH 4/6] solve issues caused due to resolve conflicts --- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 2 -- clang/test/CodeGen/aix-builtin-mapping.c | 2 +- clang/test/CodeGen/logb_scalbn.c | 12 ++++-------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index c72a746b6464d..08fca6df485b8 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -76,7 +76,6 @@ static bool popToAPSInt(InterpState &S, QualType T, APSInt &Out) { return popToAPSInt(S.Stk, *S.getContext().classify(T), Out); } - /// Check for common reasons a pointer can't be read from, which /// are usually not diagnosed in a builtin function. static bool isReadable(const Pointer &P) { @@ -156,7 +155,6 @@ static void assignIntegral(InterpState &S, const Pointer &Dest, PrimType ValueT, } } - static QualType getElemType(const Pointer &P) { const Descriptor *Desc = P.getFieldDesc(); QualType T = Desc->getType(); diff --git a/clang/test/CodeGen/aix-builtin-mapping.c b/clang/test/CodeGen/aix-builtin-mapping.c index cc1cc1a44f32c..f72b7bdca89fb 100644 --- a/clang/test/CodeGen/aix-builtin-mapping.c +++ b/clang/test/CodeGen/aix-builtin-mapping.c @@ -19,4 +19,4 @@ int main() // CHECK: %{{.+}} = call { double, double } @llvm.modf.f64(double 1.000000e+00) // CHECK: %{{.+}} = call { double, i32 } @llvm.frexp.f64.i32(double 0.000000e+00) -// CHECK: %{{.+}} = call double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 1) +// CHECK: store double 2.000000e+00, ptr %returnValue, align 8 diff --git a/clang/test/CodeGen/logb_scalbn.c b/clang/test/CodeGen/logb_scalbn.c index d4d58f5c773de..28afcaf0d55ce 100644 --- a/clang/test/CodeGen/logb_scalbn.c +++ b/clang/test/CodeGen/logb_scalbn.c @@ -1340,16 +1340,14 @@ void test_scalbnf_var3(float a, int b) { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[D1:%.*]] = alloca double, align 8, addrspace(5) // CHECK-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// CHECK-NEXT: [[TMP0:%.*]] = call double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10) -// CHECK-NEXT: store double [[TMP0]], ptr [[D1_ASCAST]], align 8 +// CHECK-NEXT: store double 1.761280e+04, ptr [[D1_ASCAST]], align 8 // CHECK-NEXT: ret void // DEFAULT-LABEL: define dso_local void @test_scalbn( // DEFAULT-SAME: ) #[[ATTR0]] { // DEFAULT-NEXT: [[ENTRY:.*:]] // DEFAULT-NEXT: [[D1:%.*]] = alloca double, align 8, addrspace(5) // DEFAULT-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// DEFAULT-NEXT: [[TMP0:%.*]] = call double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10) -// DEFAULT-NEXT: store double [[TMP0]], ptr [[D1_ASCAST]], align 8 +// DEFAULT-NEXT: store double 1.761280e+04, ptr [[D1_ASCAST]], align 8 // DEFAULT-NEXT: ret void // // IGNORE-LABEL: define dso_local void @test_scalbn( @@ -1365,8 +1363,7 @@ void test_scalbnf_var3(float a, int b) { // STRICT-NEXT: [[ENTRY:.*:]] // STRICT-NEXT: [[D1:%.*]] = alloca double, align 8, addrspace(5) // STRICT-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// STRICT-NEXT: [[TMP0:%.*]] = call double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10) -// STRICT-NEXT: store double [[TMP0]], ptr [[D1_ASCAST]], align 8 +// STRICT-NEXT: store double 1.761280e+04, ptr [[D1_ASCAST]], align 8 // STRICT-NEXT: ret void // // MAYTRAP-LABEL: define dso_local void @test_scalbn( @@ -1392,8 +1389,7 @@ void test_scalbnf_var3(float a, int b) { // AMDGCNSPIRV-DEFAULT-NEXT: [[ENTRY:.*:]] // AMDGCNSPIRV-DEFAULT-NEXT: [[D1:%.*]] = alloca double, align 8 // AMDGCNSPIRV-DEFAULT-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr [[D1]] to ptr addrspace(4) -// AMDGCNSPIRV-DEFAULT-NEXT: [[TMP0:%.*]] = call addrspace(4) double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10) -// AMDGCNSPIRV-DEFAULT-NEXT: store double [[TMP0]], ptr addrspace(4) [[D1_ASCAST]], align 8 +// AMDGCNSPIRV-DEFAULT-NEXT: store double 1.761280e+04, ptr addrspace(4) [[D1_ASCAST]], align 8 // AMDGCNSPIRV-DEFAULT-NEXT: ret void // // AMDGCNSPIRV-IGNORE-LABEL: define spir_func void @test_scalbn( >From 92068b61f2554a59229130102ff16f08e0899b52 Mon Sep 17 00:00:00 2001 From: Serosh-commits <[email protected]> Date: Wed, 29 Apr 2026 04:26:15 +0530 Subject: [PATCH 5/6] update test(folding) --- clang/test/CodeGen/logb_scalbn.c | 48 +++++++++++--------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/clang/test/CodeGen/logb_scalbn.c b/clang/test/CodeGen/logb_scalbn.c index 28afcaf0d55ce..143fd54adba98 100644 --- a/clang/test/CodeGen/logb_scalbn.c +++ b/clang/test/CodeGen/logb_scalbn.c @@ -760,16 +760,14 @@ void test_logb_var(double a) { // CHECK-NEXT: [[ENTRY:.*:]] // CHECK-NEXT: [[D1:%.*]] = alloca float, align 4, addrspace(5) // CHECK-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// CHECK-NEXT: [[TMP0:%.*]] = call float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10) -// CHECK-NEXT: store float [[TMP0]], ptr [[D1_ASCAST]], align 4 +// CHECK-NEXT: store float 0x40D0B33340000000, ptr [[D1_ASCAST]], align 4 // CHECK-NEXT: ret void // DEFAULT-LABEL: define dso_local void @test_scalbnf( // DEFAULT-SAME: ) #[[ATTR0]] { // DEFAULT-NEXT: [[ENTRY:.*:]] // DEFAULT-NEXT: [[D1:%.*]] = alloca float, align 4, addrspace(5) // DEFAULT-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// DEFAULT-NEXT: [[TMP0:%.*]] = call float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10) -// DEFAULT-NEXT: store float [[TMP0]], ptr [[D1_ASCAST]], align 4 +// DEFAULT-NEXT: store float 0x40D0B33340000000, ptr [[D1_ASCAST]], align 4 // DEFAULT-NEXT: ret void // // IGNORE-LABEL: define dso_local void @test_scalbnf( @@ -785,8 +783,7 @@ void test_logb_var(double a) { // STRICT-NEXT: [[ENTRY:.*:]] // STRICT-NEXT: [[D1:%.*]] = alloca float, align 4, addrspace(5) // STRICT-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// STRICT-NEXT: [[TMP0:%.*]] = call float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10) -// STRICT-NEXT: store float [[TMP0]], ptr [[D1_ASCAST]], align 4 +// STRICT-NEXT: store float 0x40D0B33340000000, ptr [[D1_ASCAST]], align 4 // STRICT-NEXT: ret void // // MAYTRAP-LABEL: define dso_local void @test_scalbnf( @@ -794,8 +791,7 @@ void test_logb_var(double a) { // MAYTRAP-NEXT: [[ENTRY:.*:]] // MAYTRAP-NEXT: [[D1:%.*]] = alloca float, align 4, addrspace(5) // MAYTRAP-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// MAYTRAP-NEXT: [[TMP0:%.*]] = call float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10) -// MAYTRAP-NEXT: store float [[TMP0]], ptr [[D1_ASCAST]], align 4 +// MAYTRAP-NEXT: store float 0x40D0B33340000000, ptr [[D1_ASCAST]], align 4 // MAYTRAP-NEXT: ret void // // ERRNO-LABEL: define dso_local void @test_scalbnf( @@ -803,8 +799,7 @@ void test_logb_var(double a) { // ERRNO-NEXT: [[ENTRY:.*:]] // ERRNO-NEXT: [[D1:%.*]] = alloca float, align 4, addrspace(5) // ERRNO-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// ERRNO-NEXT: [[CALL:%.*]] = call float @scalbnf(float noundef 0x4030B33340000000, i32 noundef 10) #[[ATTR2]] -// ERRNO-NEXT: store float [[CALL]], ptr [[D1_ASCAST]], align 4 +// ERRNO-NEXT: store float 0x40D0B33340000000, ptr [[D1_ASCAST]], align 4 // ERRNO-NEXT: ret void // // AMDGCNSPIRV-DEFAULT-LABEL: define spir_func void @test_scalbnf( @@ -812,8 +807,7 @@ void test_logb_var(double a) { // AMDGCNSPIRV-DEFAULT-NEXT: [[ENTRY:.*:]] // AMDGCNSPIRV-DEFAULT-NEXT: [[D1:%.*]] = alloca float, align 4 // AMDGCNSPIRV-DEFAULT-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr [[D1]] to ptr addrspace(4) -// AMDGCNSPIRV-DEFAULT-NEXT: [[TMP0:%.*]] = call addrspace(4) float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10) -// AMDGCNSPIRV-DEFAULT-NEXT: store float [[TMP0]], ptr addrspace(4) [[D1_ASCAST]], align 4 +// AMDGCNSPIRV-DEFAULT-NEXT: store float 0x40D0B33340000000, ptr addrspace(4) [[D1_ASCAST]], align 4 // AMDGCNSPIRV-DEFAULT-NEXT: ret void // // AMDGCNSPIRV-IGNORE-LABEL: define spir_func void @test_scalbnf( @@ -821,8 +815,7 @@ void test_logb_var(double a) { // AMDGCNSPIRV-IGNORE-NEXT: [[ENTRY:.*:]] // AMDGCNSPIRV-IGNORE-NEXT: [[D1:%.*]] = alloca float, align 4 // AMDGCNSPIRV-IGNORE-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr [[D1]] to ptr addrspace(4) -// AMDGCNSPIRV-IGNORE-NEXT: [[TMP0:%.*]] = call addrspace(4) float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10) -// AMDGCNSPIRV-IGNORE-NEXT: store float [[TMP0]], ptr addrspace(4) [[D1_ASCAST]], align 4 +// AMDGCNSPIRV-IGNORE-NEXT: store float 0x40D0B33340000000, ptr addrspace(4) [[D1_ASCAST]], align 4 // AMDGCNSPIRV-IGNORE-NEXT: ret void // // AMDGCNSPIRV-STRICT-LABEL: define spir_func void @test_scalbnf( @@ -830,8 +823,7 @@ void test_logb_var(double a) { // AMDGCNSPIRV-STRICT-NEXT: [[ENTRY:.*:]] // AMDGCNSPIRV-STRICT-NEXT: [[D1:%.*]] = alloca float, align 4 // AMDGCNSPIRV-STRICT-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr [[D1]] to ptr addrspace(4) -// AMDGCNSPIRV-STRICT-NEXT: [[TMP0:%.*]] = call addrspace(4) float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10) -// AMDGCNSPIRV-STRICT-NEXT: store float [[TMP0]], ptr addrspace(4) [[D1_ASCAST]], align 4 +// AMDGCNSPIRV-STRICT-NEXT: store float 0x40D0B33340000000, ptr addrspace(4) [[D1_ASCAST]], align 4 // AMDGCNSPIRV-STRICT-NEXT: ret void // // AMDGCNSPIRV-MAYTRAP-LABEL: define spir_func void @test_scalbnf( @@ -839,8 +831,7 @@ void test_logb_var(double a) { // AMDGCNSPIRV-MAYTRAP-NEXT: [[ENTRY:.*:]] // AMDGCNSPIRV-MAYTRAP-NEXT: [[D1:%.*]] = alloca float, align 4 // AMDGCNSPIRV-MAYTRAP-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr [[D1]] to ptr addrspace(4) -// AMDGCNSPIRV-MAYTRAP-NEXT: [[TMP0:%.*]] = call addrspace(4) float @llvm.ldexp.f32.i32(float 0x4030B33340000000, i32 10) -// AMDGCNSPIRV-MAYTRAP-NEXT: store float [[TMP0]], ptr addrspace(4) [[D1_ASCAST]], align 4 +// AMDGCNSPIRV-MAYTRAP-NEXT: store float 0x40D0B33340000000, ptr addrspace(4) [[D1_ASCAST]], align 4 // AMDGCNSPIRV-MAYTRAP-NEXT: ret void // // AMDGCNSPIRV-ERRNO-LABEL: define spir_func void @test_scalbnf( @@ -848,8 +839,7 @@ void test_logb_var(double a) { // AMDGCNSPIRV-ERRNO-NEXT: [[ENTRY:.*:]] // AMDGCNSPIRV-ERRNO-NEXT: [[D1:%.*]] = alloca float, align 4 // AMDGCNSPIRV-ERRNO-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr [[D1]] to ptr addrspace(4) -// AMDGCNSPIRV-ERRNO-NEXT: [[CALL:%.*]] = call spir_func addrspace(4) float @scalbnf(float noundef 0x4030B33340000000, i32 noundef 10) #[[ATTR2]] -// AMDGCNSPIRV-ERRNO-NEXT: store float [[CALL]], ptr addrspace(4) [[D1_ASCAST]], align 4 +// AMDGCNSPIRV-ERRNO-NEXT: store float 0x40D0B33340000000, ptr addrspace(4) [[D1_ASCAST]], align 4 // AMDGCNSPIRV-ERRNO-NEXT: ret void // void test_scalbnf() { @@ -1371,8 +1361,7 @@ void test_scalbnf_var3(float a, int b) { // MAYTRAP-NEXT: [[ENTRY:.*:]] // MAYTRAP-NEXT: [[D1:%.*]] = alloca double, align 8, addrspace(5) // MAYTRAP-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// MAYTRAP-NEXT: [[TMP0:%.*]] = call double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10) -// MAYTRAP-NEXT: store double [[TMP0]], ptr [[D1_ASCAST]], align 8 +// MAYTRAP-NEXT: store double 1.761280e+04, ptr [[D1_ASCAST]], align 8 // MAYTRAP-NEXT: ret void // // ERRNO-LABEL: define dso_local void @test_scalbn( @@ -1380,8 +1369,7 @@ void test_scalbnf_var3(float a, int b) { // ERRNO-NEXT: [[ENTRY:.*:]] // ERRNO-NEXT: [[D1:%.*]] = alloca double, align 8, addrspace(5) // ERRNO-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[D1]] to ptr -// ERRNO-NEXT: [[CALL:%.*]] = call double @scalbn(double noundef 1.720000e+01, i32 noundef 10) #[[ATTR2]] -// ERRNO-NEXT: store double [[CALL]], ptr [[D1_ASCAST]], align 8 +// ERRNO-NEXT: store double 1.761280e+04, ptr [[D1_ASCAST]], align 8 // ERRNO-NEXT: ret void // // AMDGCNSPIRV-DEFAULT-LABEL: define spir_func void @test_scalbn( @@ -1397,8 +1385,7 @@ void test_scalbnf_var3(float a, int b) { // AMDGCNSPIRV-IGNORE-NEXT: [[ENTRY:.*:]] // AMDGCNSPIRV-IGNORE-NEXT: [[D1:%.*]] = alloca double, align 8 // AMDGCNSPIRV-IGNORE-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr [[D1]] to ptr addrspace(4) -// AMDGCNSPIRV-IGNORE-NEXT: [[TMP0:%.*]] = call addrspace(4) double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10) -// AMDGCNSPIRV-IGNORE-NEXT: store double [[TMP0]], ptr addrspace(4) [[D1_ASCAST]], align 8 +// AMDGCNSPIRV-IGNORE-NEXT: store double 1.761280e+04, ptr addrspace(4) [[D1_ASCAST]], align 8 // AMDGCNSPIRV-IGNORE-NEXT: ret void // // AMDGCNSPIRV-STRICT-LABEL: define spir_func void @test_scalbn( @@ -1406,8 +1393,7 @@ void test_scalbnf_var3(float a, int b) { // AMDGCNSPIRV-STRICT-NEXT: [[ENTRY:.*:]] // AMDGCNSPIRV-STRICT-NEXT: [[D1:%.*]] = alloca double, align 8 // AMDGCNSPIRV-STRICT-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr [[D1]] to ptr addrspace(4) -// AMDGCNSPIRV-STRICT-NEXT: [[TMP0:%.*]] = call addrspace(4) double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10) -// AMDGCNSPIRV-STRICT-NEXT: store double [[TMP0]], ptr addrspace(4) [[D1_ASCAST]], align 8 +// AMDGCNSPIRV-STRICT-NEXT: store double 1.761280e+04, ptr addrspace(4) [[D1_ASCAST]], align 8 // AMDGCNSPIRV-STRICT-NEXT: ret void // // AMDGCNSPIRV-MAYTRAP-LABEL: define spir_func void @test_scalbn( @@ -1415,8 +1401,7 @@ void test_scalbnf_var3(float a, int b) { // AMDGCNSPIRV-MAYTRAP-NEXT: [[ENTRY:.*:]] // AMDGCNSPIRV-MAYTRAP-NEXT: [[D1:%.*]] = alloca double, align 8 // AMDGCNSPIRV-MAYTRAP-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr [[D1]] to ptr addrspace(4) -// AMDGCNSPIRV-MAYTRAP-NEXT: [[TMP0:%.*]] = call addrspace(4) double @llvm.ldexp.f64.i32(double 1.720000e+01, i32 10) -// AMDGCNSPIRV-MAYTRAP-NEXT: store double [[TMP0]], ptr addrspace(4) [[D1_ASCAST]], align 8 +// AMDGCNSPIRV-MAYTRAP-NEXT: store double 1.761280e+04, ptr addrspace(4) [[D1_ASCAST]], align 8 // AMDGCNSPIRV-MAYTRAP-NEXT: ret void // // AMDGCNSPIRV-ERRNO-LABEL: define spir_func void @test_scalbn( @@ -1424,8 +1409,7 @@ void test_scalbnf_var3(float a, int b) { // AMDGCNSPIRV-ERRNO-NEXT: [[ENTRY:.*:]] // AMDGCNSPIRV-ERRNO-NEXT: [[D1:%.*]] = alloca double, align 8 // AMDGCNSPIRV-ERRNO-NEXT: [[D1_ASCAST:%.*]] = addrspacecast ptr [[D1]] to ptr addrspace(4) -// AMDGCNSPIRV-ERRNO-NEXT: [[CALL:%.*]] = call spir_func addrspace(4) double @scalbn(double noundef 1.720000e+01, i32 noundef 10) #[[ATTR2]] -// AMDGCNSPIRV-ERRNO-NEXT: store double [[CALL]], ptr addrspace(4) [[D1_ASCAST]], align 8 +// AMDGCNSPIRV-ERRNO-NEXT: store double 1.761280e+04, ptr addrspace(4) [[D1_ASCAST]], align 8 // AMDGCNSPIRV-ERRNO-NEXT: ret void // void test_scalbn() { >From 6075ee97b695a6fac951f218da3fc6a8fe943475 Mon Sep 17 00:00:00 2001 From: Serosh-commits <[email protected]> Date: Wed, 29 Apr 2026 21:53:42 +0530 Subject: [PATCH 6/6] address feedback --- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 48 +++++++++---------- .../test/SemaCXX/constexpr-cmath-builtins.cpp | 6 ++- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 08fca6df485b8..967afb5fd71e0 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -812,12 +812,13 @@ static bool interp__builtin_frexp(InterpState &S, CodePtr OpPC, APFloat F = frexp(Val.getAPFloat(), Exp, RM); - if (!Ptr.isDummy()) { - QualType ExpType = Call->getArg(1)->getType()->getPointeeType(); - PrimType ExpT = *S.getContext().classify(ExpType); - assignIntegral(S, Ptr, ExpT, APSInt::get(Exp)); - Ptr.initialize(); - } + if (Ptr.isDummy()) + return false; + + QualType ExpType = Call->getArg(1)->getType()->getPointeeType(); + PrimType ExpT = *S.getContext().classify(ExpType); + assignIntegral(S, Ptr, ExpT, APSInt::get(Exp)); + Ptr.initialize(); Floating Result = S.allocFloat(F.getSemantics()); Result.copy(F); @@ -835,10 +836,11 @@ static bool interp__builtin_modf(InterpState &S, CodePtr OpPC, APFloat Integral = F; Integral.roundToIntegral(APFloat::rmTowardZero); - if (!Ptr.isDummy()) { - Ptr.deref<Floating>().copy(Integral); - Ptr.initialize(); - } + if (Ptr.isDummy()) + return false; + + Ptr.deref<Floating>().copy(Integral); + Ptr.initialize(); if (F.isInfinity()) { Floating Fraction = S.allocFloat(F.getSemantics()); @@ -957,16 +959,17 @@ static bool interp__builtin_remquo(InterpState &S, CodePtr OpPC, else Q.roundToIntegral(APFloat::rmNearestTiesToEven); - if (!Ptr.isDummy()) { - QualType QuoType = Call->getArg(2)->getType()->getPointeeType(); - APSInt QuoInt(S.getASTContext().getTypeSize(QuoType), false); - bool IsExact = false; - Q.convertToInteger(QuoInt, APFloat::rmTowardZero, &IsExact); + if (Ptr.isDummy()) + return false; - PrimType QuoT = *S.getContext().classify(QuoType); - assignIntegral(S, Ptr, QuoT, QuoInt); - Ptr.initialize(); - } + QualType QuoType = Call->getArg(2)->getType()->getPointeeType(); + APSInt QuoInt(S.getASTContext().getTypeSize(QuoType), /*IsUnsigned=*/false); + bool IsExact = false; + Q.convertToInteger(QuoInt, APFloat::rmTowardZero, &IsExact); + + PrimType QuoT = *S.getContext().classify(QuoType); + assignIntegral(S, Ptr, QuoT, QuoInt); + Ptr.initialize(); APFloat R = LHS.getAPFloat(); R.remainder(RHS.getAPFloat()); @@ -1020,11 +1023,8 @@ static bool interp__builtin_lrint(InterpState &S, CodePtr OpPC, APFloat::opStatus Status = F.convertToInteger(IntVal, RM, &IsExact); if (Status & APFloat::opInvalidOp) { - if (S.diagnosing()) { - auto Loc = S.Current->getSource(OpPC); - S.CCEDiag(Loc, diag::note_constexpr_float_arithmetic) - << (F.isNaN() ? 1 : 0); - } + auto Loc = S.Current->getSource(OpPC); + S.CCEDiag(Loc, diag::note_constexpr_float_arithmetic) << F.isNaN(); } pushInteger(S, IntVal, Call->getType()); diff --git a/clang/test/SemaCXX/constexpr-cmath-builtins.cpp b/clang/test/SemaCXX/constexpr-cmath-builtins.cpp index 79f28d795e179..0c64659da79ef 100644 --- a/clang/test/SemaCXX/constexpr-cmath-builtins.cpp +++ b/clang/test/SemaCXX/constexpr-cmath-builtins.cpp @@ -1,7 +1,6 @@ // RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify -std=c++20 %s // RUN: %clang_cc1 -verify -std=c++20 %s -// expected-no-diagnostics static_assert(__builtin_nearbyint(1.1) == 1.0); static_assert(__builtin_nearbyint(1.9) == 2.0); @@ -185,3 +184,8 @@ constexpr bool test_remquo_nan() { return __builtin_isnan(rem); } static_assert(test_remquo_nan()); + +namespace LRoundDiagnostic { + constexpr int i = __builtin_lround(1e30); // expected-error {{constexpr variable 'i' must be initialized by a constant expression}} \ + // expected-note {{floating point arithmetic produces an infinity}} +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
