llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Chaitanya Koparkar (ckoparkar) <details> <summary>Changes</summary> Fixes #<!-- -->153151. --- Full diff: https://github.com/llvm/llvm-project/pull/153572.diff 6 Files Affected: - (modified) clang/include/clang/Basic/Builtins.td (+2-2) - (modified) clang/lib/AST/ByteCode/InterpBuiltin.cpp (+81) - (modified) clang/lib/AST/ExprConstShared.h (+4) - (modified) clang/lib/AST/ExprConstant.cpp (+77) - (modified) clang/test/Sema/constant-builtins-vector.cpp (+48) - (modified) llvm/include/llvm/ADT/APSInt.h (+6) ``````````diff diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 84206cf8b368b..c5ad9a5d59dea 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -1516,13 +1516,13 @@ def ElementwiseSubSat : Builtin { def ElementwiseFshl : Builtin { let Spellings = ["__builtin_elementwise_fshl"]; - let Attributes = [NoThrow, Const, CustomTypeChecking]; + let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr]; let Prototype = "void(...)"; } def ElementwiseFshr : Builtin { let Spellings = ["__builtin_elementwise_fshr"]; - 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..015f0443ede54 100644 --- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp +++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp @@ -2399,6 +2399,83 @@ static bool interp__builtin_elementwise_maxmin(InterpState &S, CodePtr OpPC, return true; } +static bool interp__builtin_elementwise_fsh(InterpState &S, CodePtr OpPC, + const CallExpr *Call, + unsigned BuiltinID) { + assert(Call->getNumArgs() == 3); + + const QualType Arg1Type = Call->getArg(0)->getType(); + const QualType Arg2Type = Call->getArg(1)->getType(); + const QualType Arg3Type = Call->getArg(2)->getType(); + + // Non-vector integer types. + if (!Arg1Type->isVectorType()) { + assert(!Arg2Type->isVectorType()); + assert(!Arg3Type->isVectorType()); + + APSInt Shift = popToAPSInt( + S.Stk, *S.getContext().classify(Call->getArg(2)->getType())); + APSInt Lo = popToAPSInt( + S.Stk, *S.getContext().classify(Call->getArg(1)->getType())); + APSInt Hi = popToAPSInt( + S.Stk, *S.getContext().classify(Call->getArg(0)->getType())); + APSInt Result; + if (BuiltinID == Builtin::BI__builtin_elementwise_fshl) { + Result = HandleFshl(Hi, Lo, Shift); + } else if (BuiltinID == Builtin::BI__builtin_elementwise_fshr) { + Result = HandleFshr(Hi, Lo, Shift); + } else { + llvm_unreachable("Wrong builtin ID"); + } + pushInteger(S, Result, Call->getType()); + return true; + } + + // Vector type. + assert(Arg1Type->isVectorType() && + Arg2Type->isVectorType() && + Arg3Type->isVectorType()); + + const VectorType *VecT = Arg1Type->castAs<VectorType>(); + PrimType ElemT = *S.getContext().classify(VecT->getElementType()); + unsigned NumElems = VecT->getNumElements(); + + assert(VecT->getElementType() == + Arg2Type->castAs<VectorType>()->getElementType() && + VecT->getElementType() == + Arg3Type->castAs<VectorType>()->getElementType()); + assert(NumElems == Arg2Type->castAs<VectorType>()->getNumElements() && + NumElems == Arg3Type->castAs<VectorType>()->getNumElements()); + assert(VecT->getElementType()->isIntegralOrEnumerationType()); + + const Pointer &VecShift = S.Stk.pop<Pointer>(); + const Pointer &VecLo = S.Stk.pop<Pointer>(); + const Pointer &VecHi = S.Stk.pop<Pointer>(); + const Pointer &Dst = S.Stk.peek<Pointer>(); + for (unsigned I = 0; I != NumElems; ++I) { + APSInt Hi; + APSInt Lo; + APSInt Shift; + INT_TYPE_SWITCH_NO_BOOL(ElemT, { + Hi = VecHi.elem<T>(I).toAPSInt(); + Lo = VecLo.elem<T>(I).toAPSInt(); + Shift = VecShift.elem<T>(I).toAPSInt(); + }); + APSInt Result; + if (BuiltinID == Builtin::BI__builtin_elementwise_fshl) { + Result = HandleFshl(Hi, Lo, Shift); + } else if (BuiltinID == Builtin::BI__builtin_elementwise_fshr) { + Result = HandleFshr(Hi, Lo, Shift); + } else { + llvm_unreachable("Wrong builtin ID"); + } + INT_TYPE_SWITCH_NO_BOOL(ElemT, + { Dst.elem<T>(I) = static_cast<T>(Result); }); + } + Dst.initializeAllElements(); + return true; +} + bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, uint32_t BuiltinID) { if (!S.getASTContext().BuiltinInfo.isConstantEvaluated(BuiltinID)) @@ -2810,6 +2887,10 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call, case Builtin::BI__builtin_elementwise_min: return interp__builtin_elementwise_maxmin(S, OpPC, Call, BuiltinID); + case Builtin::BI__builtin_elementwise_fshl: + case Builtin::BI__builtin_elementwise_fshr: + return interp__builtin_elementwise_fsh(S, OpPC, Call, BuiltinID); + default: S.FFDiag(S.Current->getLocation(OpPC), diag::note_invalid_subexpr_in_const_expr) diff --git a/clang/lib/AST/ExprConstShared.h b/clang/lib/AST/ExprConstShared.h index 401ae629c86bf..a1c5607ced700 100644 --- a/clang/lib/AST/ExprConstShared.h +++ b/clang/lib/AST/ExprConstShared.h @@ -18,6 +18,7 @@ namespace llvm { class APFloat; +class APSInt; } namespace clang { class QualType; @@ -71,6 +72,9 @@ void HandleComplexComplexDiv(llvm::APFloat A, llvm::APFloat B, llvm::APFloat C, llvm::APFloat D, llvm::APFloat &ResR, llvm::APFloat &ResI); +llvm::APSInt HandleFshl(llvm::APSInt Hi, llvm::APSInt Lo, llvm::APSInt Shift); +llvm::APSInt HandleFshr(llvm::APSInt Hi, llvm::APSInt Lo, llvm::APSInt Shift); + CharUnits GetAlignOfExpr(const ASTContext &Ctx, const Expr *E, UnaryExprOrTypeTrait ExprKind); diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 36dd0f5d7a065..083d84f7375fe 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -11723,6 +11723,39 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) { return Success(APValue(ResultElements.data(), ResultElements.size()), E); } + case Builtin::BI__builtin_elementwise_fshl: + case Builtin::BI__builtin_elementwise_fshr: { + APValue SourceHi, SourceLo, SourceShift; + if (!EvaluateAsRValue(Info, E->getArg(0), SourceHi) || + !EvaluateAsRValue(Info, E->getArg(1), SourceLo) || + !EvaluateAsRValue(Info, E->getArg(2), SourceShift)) + return false; + + QualType DestEltTy = E->getType()->castAs<VectorType>()->getElementType(); + + if (!DestEltTy->isIntegerType()) + return false; + + unsigned SourceLen = SourceHi.getVectorLength(); + SmallVector<APValue> ResultElements; + ResultElements.reserve(SourceLen); + + for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) { + APSInt Hi = SourceHi.getVectorElt(EltNum).getInt(); + APSInt Lo = SourceLo.getVectorElt(EltNum).getInt(); + APSInt Shift = SourceShift.getVectorElt(EltNum).getInt(); + switch (E->getBuiltinCallee()) { + case Builtin::BI__builtin_elementwise_fshl: + ResultElements.push_back(APValue(HandleFshl(Hi, Lo, Shift))); + break; + case Builtin::BI__builtin_elementwise_fshr: + ResultElements.push_back(APValue(HandleFshr(Hi, Lo, Shift))); + break; + } + } + + return Success(APValue(ResultElements.data(), ResultElements.size()), E); + } } } @@ -13638,6 +13671,28 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E, APInt Result = std::min(LHS, RHS); return Success(APSInt(Result, !LHS.isSigned()), E); } + case Builtin::BI__builtin_elementwise_fshl: + case Builtin::BI__builtin_elementwise_fshr: { + if (!E->getArg(0)->isPRValue() || + !E->getArg(1)->isPRValue() || + !E->getArg(2)->isPRValue()) + return false; + APSInt Hi, Lo, Shift; + if (!EvaluateInteger(E->getArg(0), Hi, Info) || + !EvaluateInteger(E->getArg(1), Lo, Info) || + !EvaluateInteger(E->getArg(2), Shift, Info)) + return false; + switch (BuiltinOp) { + case Builtin::BI__builtin_elementwise_fshl: { + APSInt Result = HandleFshl(Hi, Lo, Shift); + return Success(Result, E); + } + case Builtin::BI__builtin_elementwise_fshr: { + APSInt Result = HandleFshr(Hi, Lo, Shift); + return Success(Result, E); + } + } + } case Builtin::BIstrlen: case Builtin::BIwcslen: // A call to strlen is not a constant expression. @@ -16405,6 +16460,28 @@ void HandleComplexComplexDiv(APFloat A, APFloat B, APFloat C, APFloat D, } } +// fshl(X,Y,Z): (X << (Z % BW)) | (Y >> (BW - (Z % BW))) +APSInt HandleFshl(APSInt Hi, APSInt Lo, APSInt Shift) { + bool IsUnsigned = Hi.isUnsigned(); + APSInt BitWidth(llvm::APInt(Hi.getBitWidth(), + static_cast<uint64_t>(Hi.getBitWidth())), + IsUnsigned); + return APSInt((Hi << (Shift % BitWidth)) | + (Lo >> (BitWidth - (Shift % BitWidth))), + IsUnsigned); +} + +// fshr(X,Y,Z): (X << (BW - (Z % BW))) | (Y >> (Z % BW)) +APSInt HandleFshr(APSInt Hi, APSInt Lo, APSInt Shift) { + bool IsUnsigned = Hi.isUnsigned(); + APSInt BitWidth(llvm::APInt(Hi.getBitWidth(), + static_cast<uint64_t>(Hi.getBitWidth())), + IsUnsigned); + return APSInt((Hi << (BitWidth - (Shift % BitWidth))) | + (Lo >> (Shift % BitWidth)), + IsUnsigned); +} + bool ComplexExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { if (E->isPtrMemOp() || E->isAssignmentOp() || E->getOpcode() == BO_Comma) return ExprEvaluatorBaseTy::VisitBinaryOperator(E); diff --git a/clang/test/Sema/constant-builtins-vector.cpp b/clang/test/Sema/constant-builtins-vector.cpp index bc575dca98d77..c5f9c3956780e 100644 --- a/clang/test/Sema/constant-builtins-vector.cpp +++ b/clang/test/Sema/constant-builtins-vector.cpp @@ -876,3 +876,51 @@ 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_fshl((unsigned char)255, (unsigned char)0, (unsigned char)8) == (unsigned char)255); +static_assert(__builtin_elementwise_fshl((char)127, (char)0, (char)8) == (char)127); +static_assert(__builtin_elementwise_fshl((unsigned char)0, (unsigned char)255, (unsigned char)8) == (unsigned char)0); +static_assert(__builtin_elementwise_fshl((char)0, (char)127, (char)8) == (char)0); +static_assert(__builtin_elementwise_fshr((unsigned char)255, (unsigned char)0, (unsigned char)8) == (unsigned char)0); +static_assert(__builtin_elementwise_fshr((char)127, (char)0, (char)8) == (char)0); +static_assert(__builtin_elementwise_fshr((unsigned char)0, (unsigned char)255, (unsigned char)8) == (unsigned char)255); +static_assert(__builtin_elementwise_fshr((char)0, (char)127, (char)8) == (char)127); +static_assert(__builtin_elementwise_fshl((unsigned int)4294967295, (unsigned int)0, (unsigned int)32) == (unsigned int)4294967295); +static_assert(__builtin_elementwise_fshl((int)2147483647, (int)0, (int)32) == (int)2147483647); +static_assert(__builtin_elementwise_fshl((unsigned int)0, (unsigned int)4294967295, (unsigned int)32) == (unsigned int)0); +static_assert(__builtin_elementwise_fshl((int)0, (int)2147483647, (int)32) == (int)0); +static_assert(__builtin_elementwise_fshr((unsigned int)4294967295, (unsigned int)0, (unsigned int)32) == (unsigned int)0); +static_assert(__builtin_elementwise_fshr((int)2147483647, (int)0, (int)32) == (int)0); +static_assert(__builtin_elementwise_fshr((unsigned int)0, (unsigned int)4294967295, (unsigned int)32) == (unsigned int)4294967295); +static_assert(__builtin_elementwise_fshr((int)0, (int)2147483647, (int)32) == (int)2147483647); +static_assert(__builtin_elementwise_fshl((unsigned long long)18446744073709551615ULL, (unsigned long long)0, (unsigned long long)64) == (unsigned long long)18446744073709551615ULL); +static_assert(__builtin_elementwise_fshl((long long)9223372036854775807, (long long)0, (long long)64) == (long long)9223372036854775807); +static_assert(__builtin_elementwise_fshl((unsigned long long)0, (unsigned long long)18446744073709551615ULL, (unsigned long long)64) == (unsigned long long)0); +static_assert(__builtin_elementwise_fshl((long long)0, (long long)9223372036854775807, (long long)64) == (long long)0); +static_assert(__builtin_elementwise_fshr((unsigned long long)18446744073709551615ULL, (unsigned long long)0, (unsigned long long)64) == (unsigned long long)0); +static_assert(__builtin_elementwise_fshr((long long)9223372036854775807, (long long)0, (long long)64) == (long long)0); +static_assert(__builtin_elementwise_fshr((unsigned long long)0, (unsigned long long)18446744073709551615ULL, (unsigned long long)64) == (unsigned long long)18446744073709551615ULL); +static_assert(__builtin_elementwise_fshr((long long)0, (long long)9223372036854775807, (long long)64) == (long long)9223372036854775807); +// +static_assert(__builtin_elementwise_fshl((short) 1, (short) 2, (short) 3) == (short)8); +static_assert(__builtin_elementwise_fshl((short) 2, (short) 1, (short) 3) == (short)16); +static_assert(__builtin_elementwise_fshl(1, 2 , 2) == 4); +static_assert(__builtin_elementwise_fshl(2L, 1L , 2L) == 8L); +static_assert(__builtin_elementwise_fshr((unsigned char)1, (unsigned char)2, (unsigned char)3) == (unsigned char)32); +// +constexpr vector4uchar v4s_fshl_var = + __builtin_elementwise_fshl((vector4uchar){255, 15, 0, 2}, + (vector4uchar){0, 15, 255, 1}, + (vector4uchar){15, 11, 8, 3}); +static_assert(v4s_fshl_var[0] == 128); +static_assert(v4s_fshl_var[1] == 120); +static_assert(v4s_fshl_var[2] == 0); +static_assert(v4s_fshl_var[3] == 16); +constexpr vector4uchar v4s_fshr_var = + __builtin_elementwise_fshr((vector4uchar){255, 15, 0, 1}, + (vector4uchar){0, 15, 255, 2}, + (vector4uchar){15, 11, 8, 3}); +static_assert(v4s_fshr_var[0] == 254); +static_assert(v4s_fshr_var[1] == 225); +static_assert(v4s_fshr_var[2] == 255); +static_assert(v4s_fshr_var[3] == 32); diff --git a/llvm/include/llvm/ADT/APSInt.h b/llvm/include/llvm/ADT/APSInt.h index 88a7a6e71c817..6112abed92100 100644 --- a/llvm/include/llvm/ADT/APSInt.h +++ b/llvm/include/llvm/ADT/APSInt.h @@ -152,6 +152,9 @@ class [[nodiscard]] APSInt : public APInt { APSInt operator>>(unsigned Amt) const { return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false); } + APSInt operator>>(const APSInt &Amt) const { + return IsUnsigned ? APSInt(lshr(Amt), true) : APSInt(ashr(Amt), false); + } APSInt &operator>>=(unsigned Amt) { if (IsUnsigned) lshrInPlace(Amt); @@ -211,6 +214,9 @@ class [[nodiscard]] APSInt : public APInt { APSInt operator<<(unsigned Bits) const { return APSInt(static_cast<const APInt &>(*this) << Bits, IsUnsigned); } + APSInt operator<<(const APSInt &Amt) const { + return APSInt(static_cast<const APInt &>(*this) << Amt, IsUnsigned); + } APSInt &operator<<=(unsigned Amt) { static_cast<APInt &>(*this) <<= Amt; return *this; `````````` </details> https://github.com/llvm/llvm-project/pull/153572 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits