https://github.com/Mr-Anyone updated https://github.com/llvm/llvm-project/pull/152497
>From b48993d25136a769b3b7bf8e8730be1a92ace067 Mon Sep 17 00:00:00 2001 From: Vincent <l...@viceroygroup.ca> Date: Thu, 7 Aug 2025 00:24:55 +0800 Subject: [PATCH 1/2] [clang] constexpr __builtin_elementwise_abs support Added constant evaluation of `__builtine_elementwise_abs` on integer and vector type. fixes #152276 --- clang/docs/LanguageExtensions.rst | 3 +- clang/docs/ReleaseNotes.rst | 2 + clang/include/clang/Basic/Builtins.td | 2 +- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 46 +++++++++++++++++++ clang/lib/AST/ExprConstant.cpp | 16 +++++++ .../test/CodeGen/builtins-elementwise-math.c | 2 +- clang/test/Sema/constant-builtins-vector.cpp | 6 +++ 7 files changed, 74 insertions(+), 3 deletions(-) diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst index eef3d0c4ccb9d..2db1bae918ada 100644 --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -760,7 +760,8 @@ Unless specified otherwise operation(±0) = ±0 and operation(±infinity) = ±in The integer elementwise intrinsics, including ``__builtin_elementwise_popcount``, ``__builtin_elementwise_bitreverse``, ``__builtin_elementwise_add_sat``, ``__builtin_elementwise_sub_sat``, ``__builtin_elementwise_max``, -``__builtin_elementwise_min`` can be called in a ``constexpr`` context. +``__builtin_elementwise_min``, and ``__builtin_elementwise_abs`` +can be called in a ``constexpr`` context. No implicit promotion of integer types takes place. The mixing of integer types of different sizes and signs is forbidden in binary and ternary builtins. diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index af576f817700a..b5e2f81bc0527 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -115,6 +115,8 @@ Non-comprehensive list of changes in this release ------------------------------------------------- - Added ``__builtin_elementwise_fshl`` and ``__builtin_elementwise_fshr``. +- Added `__builtin_elementwise_abs`. + - Added ``__builtin_elementwise_minnumnum`` and ``__builtin_elementwise_maxnumnum``. - Trapping UBSan (e.g. ``-fsanitize-trap=undefined``) now emits a string describing the reason for diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 84206cf8b368b..604c9cddfe051 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -1264,7 +1264,7 @@ def NondetermenisticValue : Builtin { def ElementwiseAbs : Builtin { let Spellings = ["__builtin_elementwise_abs"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index 307b77846969f..ebf82486698eb 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -1686,6 +1686,49 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_elementwise_abs(InterpState &S, CodePtr OpPC, + const InterpFrame *Frame, + const CallExpr *Call, + unsigned BuiltinID) { + // FIXME: add support of floating point + assert(!Call->getArg(0)->getType()->isFloatingType() && + "floating point is currently not supported"); + + assert(Call->getNumArgs() == 1); + if (Call->getArg(0)->getType()->isIntegerType()) { + PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); + APSInt Val = popToAPSInt(S.Stk, ArgT); + + pushInteger(S, Val.abs(), Call->getType()); + return true; + } + + // Otherwise, the argument must be a vector. + assert(Call->getArg(0)->getType()->isVectorType()); + const Pointer &Arg = S.Stk.pop<Pointer>(); + assert(Arg.getFieldDesc()->isPrimitiveArray()); + const Pointer &Dst = S.Stk.peek<Pointer>(); + assert(Dst.getFieldDesc()->isPrimitiveArray()); + assert(Arg.getFieldDesc()->getNumElems() == + Dst.getFieldDesc()->getNumElems()); + + QualType ElemType = Arg.getFieldDesc()->getElemQualType(); + PrimType ElemT = *S.getContext().classify(ElemType); + unsigned NumElems = Arg.getNumElems(); + + // FIXME: Reading from uninitialized vector elements? + for (unsigned I = 0; I != NumElems; ++I) { + INT_TYPE_SWITCH_NO_BOOL(ElemT, { + Dst.elem<T>(I) = T::from(static_cast<T>( + APSInt(Arg.elem<T>(I).toAPSInt().abs(), + ElemType->isUnsignedIntegerOrEnumerationType()))); + }); + } + Dst.initializeAllElements(); + + return true; +} + /// Can be called with an integer or vector as the first and only parameter. static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, @@ -2766,6 +2809,9 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, return interp__builtin_elementwise_popcount(S, OpPC, Frame, Call, BuiltinID); + case Builtin::BI__builtin_elementwise_abs: + return interp__builtin_elementwise_abs(S, OpPC, Frame, Call, BuiltinID); + case Builtin::BI__builtin_memcpy: case Builtin::BImemcpy: case Builtin::BI__builtin_wmemcpy: diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 36dd0f5d7a065..1c8d9706788c4 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11610,6 +11610,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { switch (E->getBuiltinCallee()) { default: return false; + case Builtin::BI__builtin_elementwise_abs: case Builtin::BI__builtin_elementwise_popcount: case Builtin::BI__builtin_elementwise_bitreverse: { APValue Source; @@ -11634,11 +11635,18 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { APValue(APSInt(Elt.reverseBits(), DestEltTy->isUnsignedIntegerOrEnumerationType()))); break; + case Builtin::BI__builtin_elementwise_abs: { + APInt Val = Source.getVectorElt(EltNum).getInt().abs(); + ResultElements.push_back(APValue( + APSInt(Val, DestEltTy->isUnsignedIntegerOrEnumerationType()))); + break; + } } } return Success(APValue(ResultElements.data(), ResultElements.size()), E); } + case Builtin::BI__builtin_elementwise_add_sat: case Builtin::BI__builtin_elementwise_sub_sat: case clang::X86::BI__builtin_ia32_pmulhuw128: @@ -13387,6 +13395,14 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, return Success(Operand, E); } + case Builtin::BI__builtin_elementwise_abs: { + APSInt Val; + if (!EvaluateInteger(E->getArg(0), Val, Info)) + return false; + + return Success(Val.abs(), E); + } + case Builtin::BI__builtin_expect: case Builtin::BI__builtin_expect_with_probability: return Visit(E->getArg(0)); diff --git a/clang/test/CodeGen/builtins-elementwise-math.c b/clang/test/CodeGen/builtins-elementwise-math.c index bb5d0351db1a2..e37e5353603a0 100644 --- a/clang/test/CodeGen/builtins-elementwise-math.c +++ b/clang/test/CodeGen/builtins-elementwise-math.c @@ -66,7 +66,7 @@ void test_builtin_elementwise_abs(float f1, float f2, double d1, double d2, // CHECK-NEXT: call i32 @llvm.abs.i32(i32 [[IA1]], i1 false) b = __builtin_elementwise_abs(int_as_one); - // CHECK: call i32 @llvm.abs.i32(i32 -10, i1 false) + // CHECK: store i32 %elt.abs11, ptr @b, align 4 b = __builtin_elementwise_abs(-10); // CHECK: [[SI:%.+]] = load i16, ptr %si.addr, align 2 diff --git a/clang/test/Sema/constant-builtins-vector.cpp b/clang/test/Sema/constant-builtins-vector.cpp index bc575dca98d77..85fb4930d09c0 100644 --- a/clang/test/Sema/constant-builtins-vector.cpp +++ b/clang/test/Sema/constant-builtins-vector.cpp @@ -876,3 +876,9 @@ static_assert(__builtin_elementwise_min(~0U, 0U) == 0U); static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_min((vector4char){1, -2, 3, -4}, (vector4char){4, -3, 2, -1})) == (LITTLE_END ? 0xFC02FD01 : 0x01FD02FC)); static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_min((vector4uchar){1, 2, 3, 4}, (vector4uchar){4, 3, 2, 1})) == 0x01020201U); static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_min((vector4short){1, -2, 3, -4}, (vector4short){4, -3, 2, -1})) == (LITTLE_END ? 0xFFFC0002FFFD0001 : 0x0001FFFD0002FFFC)); + +static_assert(__builtin_elementwise_abs(10) == 10); +static_assert(__builtin_elementwise_abs(-10) == 10); +static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_abs((vector4char){-1, -2, -3, 4})) == (LITTLE_END ? 0x04030201 : 0x01020304)); +// the absolute value of the most negative integer remains the most negative integer +static_assert(__builtin_elementwise_abs((int)(-2147483648)) == (int)(-2147483648)); >From d39ca7cd0eed88e8a8c36736f0433807233b1ce4 Mon Sep 17 00:00:00 2001 From: Vincent <l...@viceroygroup.ca> Date: Thu, 14 Aug 2025 12:11:47 +0800 Subject: [PATCH 2/2] Added Floating Point Support and Test Case --- clang/lib/AST/ByteCode/InterpBuiltin.cpp | 54 ++++++++++++-------- clang/lib/AST/ExprConstant.cpp | 21 +++++++- clang/test/Sema/constant-builtins-vector.cpp | 16 +++++- 3 files changed, 66 insertions(+), 25 deletions(-) diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp index ebf82486698eb..ede219101343a 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -598,6 +598,17 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, return true; } +static inline Floating abs(InterpState &S, const Floating &In) { + if (!In.isNegative()) + return In; + + Floating Output = S.allocFloat(In.getSemantics()); + APFloat New = In.getAPFloat(); + New.changeSign(); + Output.copy(New); + return Output; +} + // 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 @@ -606,16 +617,7 @@ static bool interp__builtin_fpclassify(InterpState &S, CodePtr OpPC, static bool interp__builtin_fabs(InterpState &S, CodePtr OpPC, const InterpFrame *Frame) { const Floating &Val = S.Stk.pop<Floating>(); - APFloat F = Val.getAPFloat(); - if (!F.isNegative()) { - S.Stk.push<Floating>(Val); - return true; - } - - Floating Result = S.allocFloat(Val.getSemantics()); - F.changeSign(); - Result.copy(F); - S.Stk.push<Floating>(Result); + S.Stk.push<Floating>(abs(S, Val)); return true; } @@ -1690,12 +1692,9 @@ static bool interp__builtin_elementwise_abs(InterpState &S, CodePtr OpPC, const InterpFrame *Frame, const CallExpr *Call, unsigned BuiltinID) { - // FIXME: add support of floating point - assert(!Call->getArg(0)->getType()->isFloatingType() && - "floating point is currently not supported"); - assert(Call->getNumArgs() == 1); - if (Call->getArg(0)->getType()->isIntegerType()) { + QualType Ty = Call->getArg(0)->getType(); + if (Ty->isIntegerType()) { PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType()); APSInt Val = popToAPSInt(S.Stk, ArgT); @@ -1703,6 +1702,13 @@ static bool interp__builtin_elementwise_abs(InterpState &S, CodePtr OpPC, return true; } + if (Ty->isFloatingType()) { + Floating Val = S.Stk.pop<Floating>(); + Floating Result = abs(S, Val); + S.Stk.push<Floating>(Result); + return true; + } + // Otherwise, the argument must be a vector. assert(Call->getArg(0)->getType()->isVectorType()); const Pointer &Arg = S.Stk.pop<Pointer>(); @@ -1715,14 +1721,18 @@ static bool interp__builtin_elementwise_abs(InterpState &S, CodePtr OpPC, QualType ElemType = Arg.getFieldDesc()->getElemQualType(); PrimType ElemT = *S.getContext().classify(ElemType); unsigned NumElems = Arg.getNumElems(); - - // FIXME: Reading from uninitialized vector elements? + // we can either have a vector of integer or a vector of floating point for (unsigned I = 0; I != NumElems; ++I) { - INT_TYPE_SWITCH_NO_BOOL(ElemT, { - Dst.elem<T>(I) = T::from(static_cast<T>( - APSInt(Arg.elem<T>(I).toAPSInt().abs(), - ElemType->isUnsignedIntegerOrEnumerationType()))); - }); + if (ElemType->isIntegerType()) { + INT_TYPE_SWITCH_NO_BOOL(ElemT, { + Dst.elem<T>(I) = T::from(static_cast<T>( + APSInt(Arg.elem<T>(I).toAPSInt().abs(), + ElemType->isUnsignedIntegerOrEnumerationType()))); + }); + } else { + Floating Val = Arg.elem<Floating>(I); + Dst.elem<Floating>(I) = abs(S, Val); + } } Dst.initializeAllElements(); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 1c8d9706788c4..3fc018bc4b7b0 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11610,7 +11610,6 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { switch (E->getBuiltinCallee()) { default: return false; - case Builtin::BI__builtin_elementwise_abs: case Builtin::BI__builtin_elementwise_popcount: case Builtin::BI__builtin_elementwise_bitreverse: { APValue Source; @@ -11646,6 +11645,25 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(APValue(ResultElements.data(), ResultElements.size()), E); } + case Builtin::BI__builtin_elementwise_abs: { + APValue Source; + if (!EvaluateAsRValue(Info, E->getArg(0), Source)) + return false; + QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + unsigned SourceLen = Source.getVectorLength(); + SmallVector<APValue, 4> ResultElements; + ResultElements.reserve(SourceLen); + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + APValue CurrentEle = Source.getVectorElt(EltNum); + APValue Val = DestEltTy->isFloatingType() + ? APValue(llvm::abs(CurrentEle.getFloat())) + : APValue(APSInt( + CurrentEle.getInt().abs(), + DestEltTy->isUnsignedIntegerOrEnumerationType())); + ResultElements.push_back(Val); + } + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } case Builtin::BI__builtin_elementwise_add_sat: case Builtin::BI__builtin_elementwise_sub_sat: @@ -15894,6 +15912,7 @@ bool FloatExprEvaluator::VisitCallExpr(const CallExpr *E) { return Error(E); return true; + case Builtin::BI__builtin_elementwise_abs: case Builtin::BI__builtin_fabs: case Builtin::BI__builtin_fabsf: case Builtin::BI__builtin_fabsl: diff --git a/clang/test/Sema/constant-builtins-vector.cpp b/clang/test/Sema/constant-builtins-vector.cpp index 85fb4930d09c0..2b7d76e36ce96 100644 --- a/clang/test/Sema/constant-builtins-vector.cpp +++ b/clang/test/Sema/constant-builtins-vector.cpp @@ -880,5 +880,17 @@ static_assert(__builtin_bit_cast(unsigned long long, __builtin_elementwise_min(( static_assert(__builtin_elementwise_abs(10) == 10); static_assert(__builtin_elementwise_abs(-10) == 10); static_assert(__builtin_bit_cast(unsigned, __builtin_elementwise_abs((vector4char){-1, -2, -3, 4})) == (LITTLE_END ? 0x04030201 : 0x01020304)); -// the absolute value of the most negative integer remains the most negative integer -static_assert(__builtin_elementwise_abs((int)(-2147483648)) == (int)(-2147483648)); +static_assert(__builtin_elementwise_abs((int)(-2147483648)) == (int)(-2147483648)); // the absolute value of the most negative integer remains the most negative integer + +// check floating point for elementwise abs +#define CHECK_FOUR_FLOAT_VEC(vec1, vec2) \ + static_assert(__builtin_fabs(vec1[0] - vec2[0]) < 1e-6); \ + static_assert(__builtin_fabs(vec1[1] - vec2[1]) < 1e-6); \ + static_assert(__builtin_fabs(vec1[2] - vec2[2]) < 1e-6); \ + static_assert(__builtin_fabs(vec1[3] - vec2[3]) < 1e-6); + +// checking floating point vector +CHECK_FOUR_FLOAT_VEC(__builtin_elementwise_abs((vector4float){-1.123, 2.123, -3.123, 4.123}), ((vector4float){1.123, 2.123, 3.123, 4.123})) +CHECK_FOUR_FLOAT_VEC(__builtin_elementwise_abs((vector4double){-1.123, 2.123, -3.123, 4.123}), ((vector4double){1.123, 2.123, 3.123, 4.123})) +static_assert(__builtin_elementwise_abs((float)-1.123) - (float)1.123 < 1e-6); // making sure one element works +#undef CHECK_FOUR_FLOAT_VEC _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits