llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: None (yronglin) <details> <summary>Changes</summary> Implement `+`, `-`, `*`, `/` , `%`, `&`, `|`, `^`, `<<`, `>>` and compound assignment operator. --- Patch is 35.67 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/108949.diff 3 Files Affected: - (modified) clang/lib/AST/ByteCode/Compiler.cpp (+112-9) - (modified) clang/test/AST/ByteCode/constexpr-vectors.cpp (+498-21) - (modified) clang/test/SemaCXX/constexpr-vectors.cpp (+1) ``````````diff diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 7e0775a51aee61..e7a6df58e6f1a6 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -1267,12 +1267,8 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) { assert(E->getLHS()->getType()->isVectorType()); assert(E->getRHS()->getType()->isVectorType()); - // FIXME: Current only support comparison binary operator, add support for - // other binary operator. - if (!E->isComparisonOp() && !E->isLogicalOp()) - return this->emitInvalid(E); // Prepare storage for result. - if (!Initializing) { + if (!Initializing || E->isCompoundAssignmentOp()) { unsigned LocalIndex = allocateTemporary(E); if (!this->emitGetPtrLocal(LocalIndex, E)) return false; @@ -1281,26 +1277,67 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) { const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); const auto *VecTy = E->getType()->getAs<VectorType>(); + auto Op = E->isCompoundAssignmentOp() + ? BinaryOperator::getOpForCompoundAssignment(E->getOpcode()) + : E->getOpcode(); // The LHS and RHS of a comparison operator must have the same type. So we // just use LHS vector element type here. PrimType ElemT = this->classifyVectorElementType(LHS->getType()); PrimType ResultElemT = this->classifyVectorElementType(E->getType()); - // Evaluate LHS and save value to LHSOffset. + // Allocate a local pointer for LHS and RHS. unsigned LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false); + unsigned RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false); + + // C++17 onwards require that we evaluate the RHS of the compound + // assignment op first. + if (E->isCompoundAssignmentOp()) { + // Evaluate RHS and save value to RHSOffset. + if (!this->visit(RHS)) + return false; + if (!this->emitSetLocal(PT_Ptr, RHSOffset, E)) + return false; + + // Evaluate LHS and save value to LHSOffset. + if (!this->visit(LHS)) + return false; + if (!this->emitSetLocal(PT_Ptr, LHSOffset, E)) + return false; + } else { + // Evaluate LHS and save value to LHSOffset. + if (!this->visit(LHS)) + return false; + if (!this->emitSetLocal(PT_Ptr, LHSOffset, E)) + return false; + + // Evaluate RHS and save value to RHSOffset. + if (!this->visit(RHS)) + return false; + if (!this->emitSetLocal(PT_Ptr, RHSOffset, E)) + return false; + } + + // Evaluate LHS and save value to LHSOffset. if (!this->visit(LHS)) return false; if (!this->emitSetLocal(PT_Ptr, LHSOffset, E)) return false; // Evaluate RHS and save value to RHSOffset. - unsigned RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false); if (!this->visit(RHS)) return false; if (!this->emitSetLocal(PT_Ptr, RHSOffset, E)) return false; + // BitAdd/BitOr/BitXor/Shl/Shr doesn't support bool type, we need perform the + // integer promotion. + bool NeedIntPromot = ElemT == PT_Bool && (E->isBitwiseOp() || E->isShiftOp()); + QualType PromotTy = + Ctx.getASTContext().getPromotedIntegerType(Ctx.getASTContext().BoolTy); + PrimType PromotT = classifyPrim(PromotTy); + PrimType OpT = NeedIntPromot ? PromotT : ElemT; + auto getElem = [=](unsigned Offset, unsigned Index) { if (!this->emitGetLocal(PT_Ptr, Offset, E)) return false; @@ -1311,16 +1348,63 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) { return false; if (!this->emitPrimCast(PT_Bool, ResultElemT, VecTy->getElementType(), E)) return false; + } else if (NeedIntPromot) { + if (!this->emitPrimCast(ElemT, PromotT, PromotTy, E)) + return false; } return true; }; +#define EMIT_ARITH_OP(OP) \ + { \ + if (ElemT == PT_Float) { \ + if (!this->emit##OP##f(getFPOptions(E), E)) \ + return false; \ + } else { \ + if (!this->emit##OP(ElemT, E)) \ + return false; \ + } \ + break; \ + } + for (unsigned I = 0; I != VecTy->getNumElements(); ++I) { if (!getElem(LHSOffset, I)) return false; if (!getElem(RHSOffset, I)) return false; - switch (E->getOpcode()) { + switch (Op) { + case BO_Add: + EMIT_ARITH_OP(Add) + case BO_Sub: + EMIT_ARITH_OP(Sub) + case BO_Mul: + EMIT_ARITH_OP(Mul) + case BO_Div: + EMIT_ARITH_OP(Div) + case BO_Rem: + if (!this->emitRem(ElemT, E)) + return false; + break; + case BO_And: + if (!this->emitBitAnd(OpT, E)) + return false; + break; + case BO_Or: + if (!this->emitBitOr(OpT, E)) + return false; + break; + case BO_Xor: + if (!this->emitBitXor(OpT, E)) + return false; + break; + case BO_Shl: + if (!this->emitShl(OpT, ElemT, E)) + return false; + break; + case BO_Shr: + if (!this->emitShr(OpT, ElemT, E)) + return false; + break; case BO_EQ: if (!this->emitEQ(ElemT, E)) return false; @@ -1356,7 +1440,7 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) { return false; break; default: - llvm_unreachable("Unsupported binary operator"); + return this->emitInvalid(E); } // The result of the comparison is a vector of the same width and number @@ -1371,10 +1455,27 @@ bool Compiler<Emitter>::VisitVectorBinOp(const BinaryOperator *E) { return false; } + // If we performed an integer promotion, we need to cast the compute result + // into result vector element type. + if (NeedIntPromot && + !this->emitPrimCast(PromotT, ResultElemT, VecTy->getElementType(), E)) + return false; + // Initialize array element with the value we just computed. if (!this->emitInitElem(ResultElemT, I, E)) return false; } + + if (E->isCompoundAssignmentOp()) { + if (!this->emitGetLocal(PT_Ptr, LHSOffset, E)) + return false; + if (!this->emitFlip(PT_Ptr, PT_Ptr, E)) + return false; + if (!this->emitMemcpy(E)) + return false; + if (!this->emitPopPtr(E)) + return false; + } return true; } @@ -2292,6 +2393,8 @@ bool Compiler<Emitter>::VisitPointerCompoundAssignOperator( template <class Emitter> bool Compiler<Emitter>::VisitCompoundAssignOperator( const CompoundAssignOperator *E) { + if (E->getType()->isVectorType()) + return VisitVectorBinOp(E); const Expr *LHS = E->getLHS(); const Expr *RHS = E->getRHS(); diff --git a/clang/test/AST/ByteCode/constexpr-vectors.cpp b/clang/test/AST/ByteCode/constexpr-vectors.cpp index 7a65b263784586..629cdd0bacb5b6 100644 --- a/clang/test/AST/ByteCode/constexpr-vectors.cpp +++ b/clang/test/AST/ByteCode/constexpr-vectors.cpp @@ -10,11 +10,217 @@ using FourI128VecSize __attribute__((vector_size(64))) = __int128; using FourCharsExtVec __attribute__((ext_vector_type(4))) = char; using FourIntsExtVec __attribute__((ext_vector_type(4))) = int; +using FourLongLongsExtVec __attribute__((ext_vector_type(4))) = long long; +using FourFloatsExtVec __attribute__((ext_vector_type(4))) = float; +using FourDoublesExtVec __attribute__((ext_vector_type(4))) = double; using FourI128ExtVec __attribute__((ext_vector_type(4))) = __int128; + +// Next a series of tests to make sure these operations are usable in +// constexpr functions. Template instantiations don't emit Winvalid-constexpr, +// so we have to do these as macros. +#define MathShiftOps(Type) \ + constexpr auto MathShiftOps##Type(Type a, Type b) { \ + a = a + b; \ + a = a - b; \ + a = a * b; \ + a = a / b; \ + b = a + 1; \ + b = a - 1; \ + b = a * 1; \ + b = a / 1; \ + a += a; \ + a -= a; \ + a *= a; \ + a /= a; \ + b += a; \ + b -= a; \ + b *= a; \ + b /= a; \ + a < b; \ + a > b; \ + a <= b; \ + a >= b; \ + a == b; \ + a != b; \ + a &&b; \ + a || b; \ + auto c = (a, b); \ + return c; \ + } + +// Ops specific to Integers. +#define MathShiftOpsInts(Type) \ + constexpr auto MathShiftopsInts##Type(Type a, Type b) { \ + a = a << b; \ + a = a >> b; \ + a = a << 3; \ + a = a >> 3; \ + a = 3 << b; \ + a = 3 >> b; \ + a <<= b; \ + a >>= b; \ + a <<= 3; \ + a >>= 3; \ + a = a % b; \ + a &b; \ + a | b; \ + a ^ b; \ + return a; \ + } + +MathShiftOps(FourCharsVecSize); +MathShiftOps(FourIntsVecSize); +MathShiftOps(FourLongLongsVecSize); +MathShiftOps(FourFloatsVecSize); +MathShiftOps(FourDoublesVecSize); +MathShiftOps(FourCharsExtVec); +MathShiftOps(FourIntsExtVec); +MathShiftOps(FourLongLongsExtVec); +MathShiftOps(FourFloatsExtVec); +MathShiftOps(FourDoublesExtVec); + +MathShiftOpsInts(FourCharsVecSize); +MathShiftOpsInts(FourIntsVecSize); +MathShiftOpsInts(FourLongLongsVecSize); +MathShiftOpsInts(FourCharsExtVec); +MathShiftOpsInts(FourIntsExtVec); +MathShiftOpsInts(FourLongLongsExtVec); + +template <typename T, typename U> +constexpr auto CmpMul(T t, U u) { + t *= u; + return t; +} +template <typename T, typename U> +constexpr auto CmpDiv(T t, U u) { + t /= u; + return t; +} +template <typename T, typename U> +constexpr auto CmpRem(T t, U u) { + t %= u; + return t; +} + +template <typename T, typename U> +constexpr auto CmpAdd(T t, U u) { + t += u; + return t; +} + +template <typename T, typename U> +constexpr auto CmpSub(T t, U u) { + t -= u; + return t; +} + +template <typename T, typename U> +constexpr auto CmpLSH(T t, U u) { + t <<= u; + return t; +} + +template <typename T, typename U> +constexpr auto CmpRSH(T t, U u) { + t >>= u; + return t; +} + +template <typename T, typename U> +constexpr auto CmpBinAnd(T t, U u) { + t &= u; + return t; +} + +template <typename T, typename U> +constexpr auto CmpBinXOr(T t, U u) { + t ^= u; + return t; +} + +template <typename T, typename U> +constexpr auto CmpBinOr(T t, U u) { + t |= u; + return t; +} + +constexpr auto CmpF(float t, float u) { + return __builtin_fabs(t - u) < 0.0001; +} + // Only int vs float makes a difference here, so we only need to test 1 of each. // Test Char to make sure the mixed-nature of shifts around char is evident. void CharUsage() { + constexpr auto a = FourCharsVecSize{6, 3, 2, 1} + + FourCharsVecSize{12, 15, 5, 7}; + static_assert(a[0] == 18 && a[1] == 18 && a[2] == 7 && a[3] == 8, ""); + + constexpr auto b = FourCharsVecSize{19, 15, 13, 12} - + FourCharsVecSize{13, 14, 5, 3}; + static_assert(b[0] == 6 && b[1] == 1 && b[2] == 8 && b[3] == 9, ""); + + constexpr auto c = FourCharsVecSize{8, 4, 2, 1} * + FourCharsVecSize{3, 4, 5, 6}; + static_assert(c[0] == 24 && c[1] == 16 && c[2] == 10 && c[3] == 6, ""); + + constexpr auto d = FourCharsVecSize{12, 12, 10, 10} / + FourCharsVecSize{6, 4, 5, 2}; + static_assert(d[0] == 2 && d[1] == 3 && d[2] == 2 && d[3] == 5, ""); + + constexpr auto e = FourCharsVecSize{12, 12, 10, 10} % + FourCharsVecSize{6, 4, 4, 3}; + static_assert(e[0] == 0 && e[1] == 0 && e[2] == 2 && e[3] == 1, ""); + + constexpr auto f = FourCharsVecSize{6, 3, 2, 1} + 3; + static_assert(f[0] == 9 && f[1] == 6 && f[2] == 5 && f[3] == 4, ""); + + constexpr auto g = FourCharsVecSize{19, 15, 12, 10} - 3; + static_assert(g[0] == 16 && g[1] == 12 && g[2] == 9 && g[3] == 7, ""); + + constexpr auto h = FourCharsVecSize{8, 4, 2, 1} * 3; + static_assert(h[0] == 24 && h[1] == 12 && h[2] == 6 && h[3] == 3, ""); + + constexpr auto j = FourCharsVecSize{12, 15, 18, 21} / 3; + static_assert(j[0] == 4 && j[1] == 5 && j[2] == 6 && j[3] == 7, ""); + + constexpr auto k = FourCharsVecSize{12, 17, 19, 22} % 3; + static_assert(k[0] == 0 && k[1] == 2 && k[2] == 1 && k[3] == 1, ""); + + constexpr auto l = 3 + FourCharsVecSize{6, 3, 2, 1}; + static_assert(l[0] == 9 && l[1] == 6 && l[2] == 5 && l[3] == 4, ""); + + constexpr auto m = 20 - FourCharsVecSize{19, 15, 12, 10}; + static_assert(m[0] == 1 && m[1] == 5 && m[2] == 8 && m[3] == 10, ""); + + constexpr auto n = 3 * FourCharsVecSize{8, 4, 2, 1}; + static_assert(n[0] == 24 && n[1] == 12 && n[2] == 6 && n[3] == 3, ""); + + constexpr auto o = 100 / FourCharsVecSize{12, 15, 18, 21}; + static_assert(o[0] == 8 && o[1] == 6 && o[2] == 5 && o[3] == 4, ""); + + constexpr auto p = 100 % FourCharsVecSize{12, 15, 18, 21}; + static_assert(p[0] == 4 && p[1] == 10 && p[2] == 10 && p[3] == 16, ""); + + constexpr auto q = FourCharsVecSize{6, 3, 2, 1} << FourCharsVecSize{1, 1, 2, 2}; + static_assert(q[0] == 12 && q[1] == 6 && q[2] == 8 && q[3] == 4, ""); + + constexpr auto r = FourCharsVecSize{19, 15, 12, 10} >> + FourCharsVecSize{1, 1, 2, 2}; + static_assert(r[0] == 9 && r[1] == 7 && r[2] == 3 && r[3] == 2, ""); + + constexpr auto s = FourCharsVecSize{6, 3, 5, 10} << 1; + static_assert(s[0] == 12 && s[1] == 6 && s[2] == 10 && s[3] == 20, ""); + + constexpr auto t = FourCharsVecSize{19, 15, 10, 20} >> 1; + static_assert(t[0] == 9 && t[1] == 7 && t[2] == 5 && t[3] == 10, ""); + + constexpr auto u = 12 << FourCharsVecSize{1, 2, 3, 3}; + static_assert(u[0] == 24 && u[1] == 48 && u[2] == 96 && u[3] == 96, ""); + + constexpr auto v = 12 >> FourCharsVecSize{1, 2, 2, 1}; + static_assert(v[0] == 6 && v[1] == 3 && v[2] == 3 && v[3] == 6, ""); + constexpr auto w = FourCharsVecSize{1, 2, 3, 4} < FourCharsVecSize{4, 3, 2, 1}; static_assert(w[0] == -1 && w[1] == -1 && w[2] == 0 && w[3] == 0, ""); @@ -57,6 +263,27 @@ void CharUsage() { constexpr auto H = FourCharsVecSize{1, 2, 3, 4} != 3; static_assert(H[0] == -1 && H[1] == -1 && H[2] == 0 && H[3] == -1, ""); + constexpr auto I = FourCharsVecSize{1, 2, 3, 4} & + FourCharsVecSize{4, 3, 2, 1}; + static_assert(I[0] == 0 && I[1] == 2 && I[2] == 2 && I[3] == 0, ""); + + constexpr auto J = FourCharsVecSize{1, 2, 3, 4} ^ + FourCharsVecSize { 4, 3, 2, 1 }; + static_assert(J[0] == 5 && J[1] == 1 && J[2] == 1 && J[3] == 5, ""); + + constexpr auto K = FourCharsVecSize{1, 2, 3, 4} | + FourCharsVecSize{4, 3, 2, 1}; + static_assert(K[0] == 5 && K[1] == 3 && K[2] == 3 && K[3] == 5, ""); + + constexpr auto L = FourCharsVecSize{1, 2, 3, 4} & 3; + static_assert(L[0] == 1 && L[1] == 2 && L[2] == 3 && L[3] == 0, ""); + + constexpr auto M = FourCharsVecSize{1, 2, 3, 4} ^ 3; + static_assert(M[0] == 2 && M[1] == 1 && M[2] == 0 && M[3] == 7, ""); + + constexpr auto N = FourCharsVecSize{1, 2, 3, 4} | 3; + static_assert(N[0] == 3 && N[1] == 3 && N[2] == 3 && N[3] == 7, ""); + constexpr auto O = FourCharsVecSize{5, 0, 6, 0} && FourCharsVecSize{5, 5, 0, 0}; static_assert(O[0] == 1 && O[1] == 0 && O[2] == 0 && O[3] == 0, ""); @@ -71,10 +298,39 @@ void CharUsage() { constexpr auto R = FourCharsVecSize{5, 0, 6, 0} || 3; static_assert(R[0] == 1 && R[1] == 1 && R[2] == 1 && R[3] == 1, ""); - constexpr auto H1 = FourCharsVecSize{-1, -1, 0, -1}; - constexpr auto InvH = -H1; + constexpr auto T = CmpMul(a, b); + static_assert(T[0] == 108 && T[1] == 18 && T[2] == 56 && T[3] == 72, ""); + + constexpr auto U = CmpDiv(a, b); + static_assert(U[0] == 3 && U[1] == 18 && U[2] == 0 && U[3] == 0, ""); + + constexpr auto V = CmpRem(a, b); + static_assert(V[0] == 0 && V[1] == 0 && V[2] == 7 && V[3] == 8, ""); + + constexpr auto X = CmpAdd(a, b); + static_assert(X[0] == 24 && X[1] == 19 && X[2] == 15 && X[3] == 17, ""); + + constexpr auto Y = CmpSub(a, b); + static_assert(Y[0] == 12 && Y[1] == 17 && Y[2] == -1 && Y[3] == -1, ""); + + constexpr auto InvH = -H; static_assert(InvH[0] == 1 && InvH[1] == 1 && InvH[2] == 0 && InvH[3] == 1, ""); + constexpr auto Z = CmpLSH(a, InvH); + static_assert(Z[0] == 36 && Z[1] == 36 && Z[2] == 7 && Z[3] == 16, ""); + + constexpr auto aa = CmpRSH(a, InvH); + static_assert(aa[0] == 9 && aa[1] == 9 && aa[2] == 7 && aa[3] == 4, ""); + + constexpr auto ab = CmpBinAnd(a, b); + static_assert(ab[0] == 2 && ab[1] == 0 && ab[2] == 0 && ab[3] == 8, ""); + + constexpr auto ac = CmpBinXOr(a, b); + static_assert(ac[0] == 20 && ac[1] == 19 && ac[2] == 15 && ac[3] == 1, ""); + + constexpr auto ad = CmpBinOr(a, b); + static_assert(ad[0] == 22 && ad[1] == 19 && ad[2] == 15 && ad[3] == 9, ""); + constexpr auto ae = ~FourCharsVecSize{1, 2, 10, 20}; static_assert(ae[0] == -2 && ae[1] == -3 && ae[2] == -11 && ae[3] == -21, ""); @@ -83,6 +339,75 @@ void CharUsage() { } void CharExtVecUsage() { + constexpr auto a = FourCharsExtVec{6, 3, 2, 1} + + FourCharsExtVec{12, 15, 5, 7}; + static_assert(a[0] == 18 && a[1] == 18 && a[2] == 7 && a[3] == 8, ""); + + constexpr auto b = FourCharsExtVec{19, 15, 13, 12} - + FourCharsExtVec{13, 14, 5, 3}; + static_assert(b[0] == 6 && b[1] == 1 && b[2] == 8 && b[3] == 9, ""); + + constexpr auto c = FourCharsExtVec{8, 4, 2, 1} * + FourCharsExtVec{3, 4, 5, 6}; + static_assert(c[0] == 24 && c[1] == 16 && c[2] == 10 && c[3] == 6, ""); + + constexpr auto d = FourCharsExtVec{12, 12, 10, 10} / + FourCharsExtVec{6, 4, 5, 2}; + static_assert(d[0] == 2 && d[1] == 3 && d[2] == 2 && d[3] == 5, ""); + + constexpr auto e = FourCharsExtVec{12, 12, 10, 10} % + FourCharsExtVec{6, 4, 4, 3}; + static_assert(e[0] == 0 && e[1] == 0 && e[2] == 2 && e[3] == 1, ""); + + constexpr auto f = FourCharsExtVec{6, 3, 2, 1} + 3; + static_assert(f[0] == 9 && f[1] == 6 && f[2] == 5 && f[3] == 4, ""); + + constexpr auto g = FourCharsExtVec{19, 15, 12, 10} - 3; + static_assert(g[0] == 16 && g[1] == 12 && g[2] == 9 && g[3] == 7, ""); + + constexpr auto h = FourCharsExtVec{8, 4, 2, 1} * 3; + static_assert(h[0] == 24 && h[1] == 12 && h[2] == 6 && h[3] == 3, ""); + + constexpr auto j = FourCharsExtVec{12, 15, 18, 21} / 3; + static_assert(j[0] == 4 && j[1] == 5 && j[2] == 6 && j[3] == 7, ""); + + constexpr auto k = FourCharsExtVec{... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/108949 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits