diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h index b2887bcc36246..ad6ad53268a86 100644 --- a/clang/include/clang/AST/TypeBase.h +++ b/clang/include/clang/AST/TypeBase.h @@ -2511,6 +2511,11 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { /// RVV vector or mask. bool isRVVVLSBuiltinType() const; + /// Determines if this is either an SVE or RVV sizeless builtin type. + bool isVLSBuiltinType() const { + return isSveVLSBuiltinType() || isRVVVLSBuiltinType(); + } + /// Returns the representative type for the element of an RVV builtin type. /// This is used to represent fixed-length RVV vectors created with the /// 'riscv_rvv_vector_bits' type attribute as VectorType. @@ -3297,6 +3302,12 @@ class BuiltinType : public Type { bool isSVECount() const { return getKind() == Kind::SveCount; } + bool isRVVBool() const { + return getKind() >= Kind::RvvBool1 && getKind() <= Kind::RvvBool64; + } + + bool isSizelessVectorBool() const { return isSVEBool() || isRVVBool(); } + /// Determines whether the given kind corresponds to a placeholder type. static bool isPlaceholderTypeKind(Kind K) { return K >= Overload; @@ -8830,7 +8841,7 @@ inline bool Type::isConstantMatrixBoolType() const { } inline bool Type::isSubscriptableVectorType() const { - return isVectorType() || isSveVLSBuiltinType(); + return isVectorType() || isVLSBuiltinType(); } inline bool Type::isMatrixType() const { diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 1a4c962801077..d9f2f48b26cfd 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -9662,7 +9662,7 @@ bool LValueExprEvaluator::VisitExtVectorElementExpr( } bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) { - if (E->getBase()->getType()->isSveVLSBuiltinType()) + if (E->getBase()->getType()->isVLSBuiltinType()) return Error(E); APSInt Index; diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 06023fc088a32..1b67282ca8c61 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -2127,8 +2127,8 @@ bool Type::hasIntegerRepresentation() const { } if (CanonicalType->isRVVVLSBuiltinType()) { const auto *VT = cast(CanonicalType); - return (VT->getKind() >= BuiltinType::RvvInt8mf8 && - VT->getKind() <= BuiltinType::RvvUint64m8); + return VT->isRVVBool() || (VT->getKind() >= BuiltinType::RvvInt8mf8 && + VT->getKind() <= BuiltinType::RvvUint64m8); } return isIntegerType(); @@ -2310,9 +2310,14 @@ bool Type::isSignedIntegerOrEnumerationType() const { bool Type::hasSignedIntegerRepresentation() const { if (const auto *VT = dyn_cast(CanonicalType)) return VT->getElementType()->isSignedIntegerOrEnumerationType(); - if (const auto *BT = dyn_cast(CanonicalType)) { switch (BT->getKind()) { +#define RVV_VECTOR_TYPE_INT(Name, Id, SingletonId, NumEls, ElBits, NF, \ + IsSigned) \ + case BuiltinType::Id: \ + return IsSigned; +#include "clang/Basic/AArch64ACLETypes.def" +#undef RVV_VECTOR_TYPE_INT #define SVE_VECTOR_TYPE_INT(Name, MangledName, Id, SingletonId, NumEls, \ ElBits, NF, IsSigned) \ case BuiltinType::Id: \ @@ -2322,7 +2327,6 @@ bool Type::hasSignedIntegerRepresentation() const { break; } } - return isSignedIntegerOrEnumerationType(); } @@ -2383,6 +2387,18 @@ bool Type::hasUnsignedIntegerRepresentation() const { return VT->getKind() >= BuiltinType::SveUint8 && VT->getKind() <= BuiltinType::SveUint64; } + if (const auto *BT = dyn_cast(CanonicalType)) { + switch (BT->getKind()) { +#define RVV_VECTOR_TYPE_INT(Name, Id, SingletonId, NumEls, ElBits, NF, \ + IsSigned) \ + case BuiltinType::Id: \ + return !IsSigned; +#include "clang/Basic/RISCVVTypes.def" +#undef RVV_VECTOR_TYPE_INT + default: + break; + } + } return isUnsignedIntegerOrEnumerationType(); } diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index c494669420282..94dadc2231ce4 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -5453,13 +5453,13 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, } } else if (LHSTy->isSubscriptableVectorType()) { if (LHSTy->isBuiltinType() && - LHSTy->getAs()->isSveVLSBuiltinType()) { + LHSTy->getAs()->isVLSBuiltinType()) { const BuiltinType *BTy = LHSTy->getAs(); - if (BTy->isSVEBool()) + if (BTy->isSizelessVectorBool()) return ExprError(Diag(LLoc, diag::err_subscript_svbool_t) << LHSExp->getSourceRange() << RHSExp->getSourceRange()); - ResultType = BTy->getSveEltType(Context); + ResultType = LHSTy->getSizelessVectorEltType(Context); } else { const VectorType *VTy = LHSTy->getAs(); ResultType = VTy->getElementType(); @@ -10587,11 +10587,11 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, assert(!isa(VT) && "ExtVectorTypes should not be handled here!"); VectorEltTy = VT->getElementType(); - } else if (VectorTy->isSveVLSBuiltinType()) { - VectorEltTy = - VectorTy->castAs()->getSveEltType(S.getASTContext()); + } else if (VectorTy->isVLSBuiltinType()) { + VectorEltTy = VectorTy->getSizelessVectorEltType(S.getASTContext()); } else { - llvm_unreachable("Only Fixed-Length and SVE Vector types are handled here"); + llvm_unreachable( + "Only Fixed-Length and sizeless vector types are handled here"); } // Reject cases where the vector element type or the scalar element type are @@ -10958,8 +10958,8 @@ QualType Sema::CheckSizelessVectorOperands(ExprResult &LHS, ExprResult &RHS, unsigned DiagID = diag::err_typecheck_invalid_operands; if ((OperationKind == ArithConvKind::Arithmetic) && - ((LHSBuiltinTy && LHSBuiltinTy->isSVEBool()) || - (RHSBuiltinTy && RHSBuiltinTy->isSVEBool()))) { + ((LHSBuiltinTy && LHSBuiltinTy->isSizelessVectorBool()) || + (RHSBuiltinTy && RHSBuiltinTy->isSizelessVectorBool()))) { Diag(Loc, DiagID) << LHSType << RHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); @@ -10968,25 +10968,25 @@ QualType Sema::CheckSizelessVectorOperands(ExprResult &LHS, ExprResult &RHS, if (Context.hasSameType(LHSType, RHSType)) return LHSType; - if (LHSType->isSveVLSBuiltinType() && !RHSType->isSveVLSBuiltinType()) { + if (LHSType->isVLSBuiltinType() && !RHSType->isVLSBuiltinType()) { if (!tryGCCVectorConvertAndSplat(*this, &RHS, &LHS)) return LHSType; } - if (RHSType->isSveVLSBuiltinType() && !LHSType->isSveVLSBuiltinType()) { + if (RHSType->isVLSBuiltinType() && !LHSType->isVLSBuiltinType()) { if (LHS.get()->isLValue() || !tryGCCVectorConvertAndSplat(*this, &LHS, &RHS)) return RHSType; } - if ((!LHSType->isSveVLSBuiltinType() && !LHSType->isRealType()) || - (!RHSType->isSveVLSBuiltinType() && !RHSType->isRealType())) { + if ((!LHSType->isVLSBuiltinType() && !LHSType->isRealType()) || + (!RHSType->isVLSBuiltinType() && !RHSType->isRealType())) { Diag(Loc, diag::err_typecheck_vector_not_convertable_non_scalar) << LHSType << RHSType << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } - if (LHSType->isSveVLSBuiltinType() && RHSType->isSveVLSBuiltinType() && + if (LHSType->isVLSBuiltinType() && RHSType->isVLSBuiltinType() && Context.getBuiltinVectorTypeInfo(LHSBuiltinTy).EC != Context.getBuiltinVectorTypeInfo(RHSBuiltinTy).EC) { Diag(Loc, diag::err_typecheck_vector_lengths_not_equal) @@ -10995,11 +10995,11 @@ QualType Sema::CheckSizelessVectorOperands(ExprResult &LHS, ExprResult &RHS, return QualType(); } - if (LHSType->isSveVLSBuiltinType() || RHSType->isSveVLSBuiltinType()) { - QualType Scalar = LHSType->isSveVLSBuiltinType() ? RHSType : LHSType; - QualType Vector = LHSType->isSveVLSBuiltinType() ? LHSType : RHSType; + if (LHSType->isVLSBuiltinType() || RHSType->isVLSBuiltinType()) { + QualType Scalar = LHSType->isVLSBuiltinType() ? RHSType : LHSType; + QualType Vector = LHSType->isVLSBuiltinType() ? LHSType : RHSType; bool ScalarOrVector = - LHSType->isSveVLSBuiltinType() && RHSType->isSveVLSBuiltinType(); + LHSType->isVLSBuiltinType() && RHSType->isVLSBuiltinType(); Diag(Loc, diag::err_typecheck_vector_not_convertable_implict_truncation) << ScalarOrVector << Scalar << Vector; @@ -11205,7 +11205,7 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, /*AllowBoolConversions*/ false, /*AllowBooleanOperation*/ false, /*ReportInvalid*/ true); - if (LHSTy->isSveVLSBuiltinType() || RHSTy->isSveVLSBuiltinType()) + if (LHSTy->isVLSBuiltinType() || RHSTy->isVLSBuiltinType()) return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign, ArithConvKind::Arithmetic); if (!IsDiv && @@ -11271,8 +11271,8 @@ QualType Sema::CheckRemainderOperands( return InvalidOperands(Loc, LHS, RHS); } - if (LHS.get()->getType()->isSveVLSBuiltinType() || - RHS.get()->getType()->isSveVLSBuiltinType()) { + if (LHS.get()->getType()->isVLSBuiltinType() || + RHS.get()->getType()->isVLSBuiltinType()) { if (LHS.get()->getType()->hasIntegerRepresentation() && RHS.get()->getType()->hasIntegerRepresentation()) return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign, @@ -11598,8 +11598,8 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, return compType; } - if (LHS.get()->getType()->isSveVLSBuiltinType() || - RHS.get()->getType()->isSveVLSBuiltinType()) { + if (LHS.get()->getType()->isVLSBuiltinType() || + RHS.get()->getType()->isVLSBuiltinType()) { QualType compType = CheckSizelessVectorOperands(LHS, RHS, Loc, CompLHSTy, ArithConvKind::Arithmetic); if (CompLHSTy) @@ -11725,8 +11725,8 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, return compType; } - if (LHS.get()->getType()->isSveVLSBuiltinType() || - RHS.get()->getType()->isSveVLSBuiltinType()) { + if (LHS.get()->getType()->isVLSBuiltinType() || + RHS.get()->getType()->isVLSBuiltinType()) { QualType compType = CheckSizelessVectorOperands(LHS, RHS, Loc, CompLHSTy, ArithConvKind::Arithmetic); if (CompLHSTy) @@ -12080,19 +12080,22 @@ static QualType checkSizelessVectorShift(Sema &S, ExprResult &LHS, QualType LHSType = LHS.get()->getType(); const BuiltinType *LHSBuiltinTy = LHSType->castAs(); - QualType LHSEleType = LHSType->isSveVLSBuiltinType() - ? LHSBuiltinTy->getSveEltType(S.getASTContext()) - : LHSType; + + QualType LHSEleType = + LHSType->isVLSBuiltinType() + ? LHSType->getSizelessVectorEltType(S.getASTContext()) + : LHSType; // Note that RHS might not be a vector QualType RHSType = RHS.get()->getType(); const BuiltinType *RHSBuiltinTy = RHSType->castAs(); - QualType RHSEleType = RHSType->isSveVLSBuiltinType() - ? RHSBuiltinTy->getSveEltType(S.getASTContext()) - : RHSType; + QualType RHSEleType = + RHSType->isVLSBuiltinType() + ? RHSType->getSizelessVectorEltType(S.getASTContext()) + : RHSType; - if ((LHSBuiltinTy && LHSBuiltinTy->isSVEBool()) || - (RHSBuiltinTy && RHSBuiltinTy->isSVEBool())) { + if ((LHSBuiltinTy && LHSBuiltinTy->isSizelessVectorBool()) || + (RHSBuiltinTy && RHSBuiltinTy->isSizelessVectorBool())) { S.Diag(Loc, diag::err_typecheck_invalid_operands) << LHSType << RHSType << LHS.get()->getSourceRange(); return QualType(); @@ -12110,7 +12113,7 @@ static QualType checkSizelessVectorShift(Sema &S, ExprResult &LHS, return QualType(); } - if (LHSType->isSveVLSBuiltinType() && RHSType->isSveVLSBuiltinType() && + if (LHSType->isVLSBuiltinType() && RHSType->isVLSBuiltinType() && (S.Context.getBuiltinVectorTypeInfo(LHSBuiltinTy).EC != S.Context.getBuiltinVectorTypeInfo(RHSBuiltinTy).EC)) { S.Diag(Loc, diag::err_typecheck_invalid_operands) @@ -12119,8 +12122,8 @@ static QualType checkSizelessVectorShift(Sema &S, ExprResult &LHS, return QualType(); } - if (!LHSType->isSveVLSBuiltinType()) { - assert(RHSType->isSveVLSBuiltinType()); + if (!LHSType->isVLSBuiltinType()) { + assert(RHSType->isVLSBuiltinType()); if (IsCompAssign) return RHSType; if (LHSEleType != RHSEleType) { @@ -12133,7 +12136,7 @@ static QualType checkSizelessVectorShift(Sema &S, ExprResult &LHS, S.Context.getScalableVectorType(LHSEleType, VecSize.getKnownMinValue()); LHS = S.ImpCastExprToType(LHS.get(), VecTy, clang::CK_VectorSplat); LHSType = VecTy; - } else if (RHSBuiltinTy && RHSBuiltinTy->isSveVLSBuiltinType()) { + } else if (RHSBuiltinTy && RHSType->isVLSBuiltinType()) { if (S.Context.getTypeSize(RHSBuiltinTy) != S.Context.getTypeSize(LHSBuiltinTy)) { S.Diag(Loc, diag::err_typecheck_vector_lengths_not_equal) @@ -12179,8 +12182,8 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, return checkVectorShift(*this, LHS, RHS, Loc, IsCompAssign); } - if (LHS.get()->getType()->isSveVLSBuiltinType() || - RHS.get()->getType()->isSveVLSBuiltinType()) + if (LHS.get()->getType()->isVLSBuiltinType() || + RHS.get()->getType()->isVLSBuiltinType()) return checkSizelessVectorShift(*this, LHS, RHS, Loc, IsCompAssign); // Shifts don't perform usual arithmetic conversions, they just do integer @@ -13798,8 +13801,8 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, return InvalidOperands(Loc, LHS, RHS); } - if (LHS.get()->getType()->isSveVLSBuiltinType() || - RHS.get()->getType()->isSveVLSBuiltinType()) { + if (LHS.get()->getType()->isVLSBuiltinType() || + RHS.get()->getType()->isVLSBuiltinType()) { if (LHS.get()->getType()->hasIntegerRepresentation() && RHS.get()->getType()->hasIntegerRepresentation()) return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign, @@ -13807,8 +13810,8 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, return InvalidOperands(Loc, LHS, RHS); } - if (LHS.get()->getType()->isSveVLSBuiltinType() || - RHS.get()->getType()->isSveVLSBuiltinType()) { + if (LHS.get()->getType()->isVLSBuiltinType() || + RHS.get()->getType()->isVLSBuiltinType()) { if (LHS.get()->getType()->hasIntegerRepresentation() && RHS.get()->getType()->hasIntegerRepresentation()) return CheckSizelessVectorOperands(LHS, RHS, Loc, IsCompAssign, @@ -16239,7 +16242,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, resultType->castAs()->getVectorKind() != VectorKind::AltiVecBool)) break; - else if (resultType->isSveVLSBuiltinType()) // SVE vectors allow + and - + else if (resultType->isVLSBuiltinType()) // Sizeless vectors allow + and - break; else if (getLangOpts().CPlusPlus && // C++ [expr.unary.op]p6 Opc == UO_Plus && resultType->isPointerType()) diff --git a/clang/test/CodeGen/RISCV/rvv-vector-arith-ops.c b/clang/test/CodeGen/RISCV/rvv-vector-arith-ops.c new file mode 100644 index 0000000000000..bdeb800264ab4 --- /dev/null +++ b/clang/test/CodeGen/RISCV/rvv-vector-arith-ops.c @@ -0,0 +1,241 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple riscv32 -target-feature +v \ +// RUN: -disable-O0-optnone \ +// RUN: -emit-llvm -o - %s | opt -S -passes=sroa | FileCheck %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +v \ +// RUN: -disable-O0-optnone \ +// RUN: -emit-llvm -o - %s | opt -S -passes=sroa | FileCheck %s + +// REQUIRES: riscv-registered-target + +#include + +// SIGNED INTEGER + +// CHECK-LABEL: @add_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[ADD:%.*]] = add [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[ADD]] +// +vint32m1_t add_i32(vint32m1_t a, vint32m1_t b) { + return a + b; +} + +// CHECK-LABEL: @sub_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SUB:%.*]] = sub [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[SUB]] +// +vint32m1_t sub_i32(vint32m1_t a, vint32m1_t b) { + return a - b; +} + +// CHECK-LABEL: @mul_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[MUL:%.*]] = mul [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[MUL]] +// +vint32m1_t mul_i32(vint32m1_t a, vint32m1_t b) { + return a * b; +} + +// CHECK-LABEL: @sdiv_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DIV:%.*]] = sdiv [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[DIV]] +// +vint32m1_t sdiv_i32(vint32m1_t a, vint32m1_t b) { + return a / b; +} + +// CHECK-LABEL: @srem_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[REM:%.*]] = srem [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[REM]] +// +vint32m1_t srem_i32(vint32m1_t a, vint32m1_t b) { + return a % b; +} + +// CHECK-LABEL: @neg_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SUB:%.*]] = sub zeroinitializer, [[A:%.*]] +// CHECK-NEXT: ret [[SUB]] +// +vint32m1_t neg_i32(vint32m1_t a) { + return -a; +} + +// UNSIGNED INTEGER + +// CHECK-LABEL: @add_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[ADD:%.*]] = add [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[ADD]] +// +vuint32m1_t add_u32(vuint32m1_t a, vuint32m1_t b) { + return a + b; +} + +// CHECK-LABEL: @udiv_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DIV:%.*]] = udiv [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[DIV]] +// +vuint32m1_t udiv_u32(vuint32m1_t a, vuint32m1_t b) { + return a / b; +} + +// CHECK-LABEL: @urem_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[REM:%.*]] = urem [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[REM]] +// +vuint32m1_t urem_u32(vuint32m1_t a, vuint32m1_t b) { + return a % b; +} + +// FLOATING POINT + +// CHECK-LABEL: @fadd_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[ADD:%.*]] = fadd [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[ADD]] +// +vfloat32m1_t fadd_f32(vfloat32m1_t a, vfloat32m1_t b) { + return a + b; +} + +// CHECK-LABEL: @fsub_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SUB:%.*]] = fsub [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[SUB]] +// +vfloat32m1_t fsub_f32(vfloat32m1_t a, vfloat32m1_t b) { + return a - b; +} + +// CHECK-LABEL: @fmul_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[MUL:%.*]] = fmul [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[MUL]] +// +vfloat32m1_t fmul_f32(vfloat32m1_t a, vfloat32m1_t b) { + return a * b; +} + +// CHECK-LABEL: @fdiv_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DIV:%.*]] = fdiv [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[DIV]] +// +vfloat32m1_t fdiv_f32(vfloat32m1_t a, vfloat32m1_t b) { + return a / b; +} + +// CHECK-LABEL: @fneg_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[FNEG:%.*]] = fneg [[A:%.*]] +// CHECK-NEXT: ret [[FNEG]] +// +vfloat32m1_t fneg_f32(vfloat32m1_t a) { + return -a; +} + +// 64-BIT ELEMENT + +// CHECK-LABEL: @add_i64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[ADD:%.*]] = add [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[ADD]] +// +vint64m1_t add_i64(vint64m1_t a, vint64m1_t b) { + return a + b; +} + +// CHECK-LABEL: @sdiv_i64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DIV:%.*]] = sdiv [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[DIV]] +// +vint64m1_t sdiv_i64(vint64m1_t a, vint64m1_t b) { + return a / b; +} + +// CHECK-LABEL: @udiv_u64( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[DIV:%.*]] = udiv [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[DIV]] +// +vuint64m1_t udiv_u64(vuint64m1_t a, vuint64m1_t b) { + return a / b; +} + +// DIFFERENT LMUL + +// CHECK-LABEL: @add_i32_m2( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[ADD:%.*]] = add [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[ADD]] +// +vint32m2_t add_i32_m2(vint32m2_t a, vint32m2_t b) { + return a + b; +} + +// SCALAR SPLAT + +// CHECK-LABEL: @add_scalar_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement poison, i32 [[B:%.*]], i64 0 +// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector [[SPLAT_SPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[ADD:%.*]] = add [[A:%.*]], [[SPLAT_SPLAT]] +// CHECK-NEXT: ret [[ADD]] +// +vint32m1_t add_scalar_i32(vint32m1_t a, int b) { + return a + b; +} + +// CHECK-LABEL: @add_scalar_lhs_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement poison, i32 [[A:%.*]], i64 0 +// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector [[SPLAT_SPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[ADD:%.*]] = add [[SPLAT_SPLAT]], [[B:%.*]] +// CHECK-NEXT: ret [[ADD]] +// +vint32m1_t add_scalar_lhs_i32(int a, vint32m1_t b) { + return a + b; +} + +// CHECK-LABEL: @mul_scalar_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement poison, i32 [[B:%.*]], i64 0 +// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector [[SPLAT_SPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[MUL:%.*]] = mul [[A:%.*]], [[SPLAT_SPLAT]] +// CHECK-NEXT: ret [[MUL]] +// +vuint32m1_t mul_scalar_u32(vuint32m1_t a, unsigned b) { + return a * b; +} + +// CHECK-LABEL: @fsub_scalar_f32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SPLAT_SPLATINSERT:%.*]] = insertelement poison, float [[B:%.*]], i64 0 +// CHECK-NEXT: [[SPLAT_SPLAT:%.*]] = shufflevector [[SPLAT_SPLATINSERT]], poison, zeroinitializer +// CHECK-NEXT: [[SUB:%.*]] = fsub [[A:%.*]], [[SPLAT_SPLAT]] +// CHECK-NEXT: ret [[SUB]] +// +vfloat32m1_t fsub_scalar_f32(vfloat32m1_t a, float b) { + return a - b; +} + +// COMPOUND ASSIGNMENT + +// CHECK-LABEL: @compound_add_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[ADD:%.*]] = add [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[ADD]] +// +vint32m1_t compound_add_i32(vint32m1_t a, vint32m1_t b) { + a += b; + return a; +} diff --git a/clang/test/CodeGen/RISCV/rvv-vector-bitwise-ops.c b/clang/test/CodeGen/RISCV/rvv-vector-bitwise-ops.c new file mode 100644 index 0000000000000..894c7e73a736b --- /dev/null +++ b/clang/test/CodeGen/RISCV/rvv-vector-bitwise-ops.c @@ -0,0 +1,87 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple riscv32 -target-feature +v \ +// RUN: -disable-O0-optnone \ +// RUN: -emit-llvm -o - %s | opt -S -passes=sroa | FileCheck %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +v \ +// RUN: -disable-O0-optnone \ +// RUN: -emit-llvm -o - %s | opt -S -passes=sroa | FileCheck %s + +// REQUIRES: riscv-registered-target + +#include + +// INTEGER + +// CHECK-LABEL: @and_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[AND:%.*]] = and [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[AND]] +// +vint32m1_t and_i32(vint32m1_t a, vint32m1_t b) { + return a & b; +} + +// CHECK-LABEL: @or_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[OR:%.*]] = or [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[OR]] +// +vint32m1_t or_i32(vint32m1_t a, vint32m1_t b) { + return a | b; +} + +// CHECK-LABEL: @xor_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[XOR:%.*]] = xor [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[XOR]] +// +vint32m1_t xor_i32(vint32m1_t a, vint32m1_t b) { + return a ^ b; +} + +// CHECK-LABEL: @not_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[NOT:%.*]] = xor [[A:%.*]], splat (i32 -1) +// CHECK-NEXT: ret [[NOT]] +// +vint32m1_t not_i32(vint32m1_t a) { + return ~a; +} + +// BOOLEAN + +// CHECK-LABEL: @and_bool( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[AND:%.*]] = and [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[AND]] +// +vbool64_t and_bool(vbool64_t a, vbool64_t b) { + return a & b; +} + +// CHECK-LABEL: @or_bool( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[OR:%.*]] = or [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[OR]] +// +vbool64_t or_bool(vbool64_t a, vbool64_t b) { + return a | b; +} + +// CHECK-LABEL: @xor_bool( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[XOR:%.*]] = xor [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[XOR]] +// +vbool64_t xor_bool(vbool64_t a, vbool64_t b) { + return a ^ b; +} + +// CHECK-LABEL: @not_bool( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[NOT:%.*]] = xor [[A:%.*]], splat (i1 true) +// CHECK-NEXT: ret [[NOT]] +// +vbool64_t not_bool(vbool64_t a) { + return ~a; +} diff --git a/clang/test/CodeGen/RISCV/rvv-vector-shift-ops.c b/clang/test/CodeGen/RISCV/rvv-vector-shift-ops.c new file mode 100644 index 0000000000000..33937ffd840aa --- /dev/null +++ b/clang/test/CodeGen/RISCV/rvv-vector-shift-ops.c @@ -0,0 +1,48 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple riscv32 -target-feature +v \ +// RUN: -disable-O0-optnone \ +// RUN: -emit-llvm -o - %s | opt -S -passes=sroa | FileCheck %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +v \ +// RUN: -disable-O0-optnone \ +// RUN: -emit-llvm -o - %s | opt -S -passes=sroa | FileCheck %s + +// REQUIRES: riscv-registered-target + +#include + +// CHECK-LABEL: @shl_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SHL:%.*]] = shl [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[SHL]] +// +vint32m1_t shl_i32(vint32m1_t a, vint32m1_t b) { + return a << b; +} + +// CHECK-LABEL: @ashr_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SHR:%.*]] = ashr [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[SHR]] +// +vint32m1_t ashr_i32(vint32m1_t a, vint32m1_t b) { + return a >> b; +} + +// CHECK-LABEL: @lshr_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SHR:%.*]] = lshr [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[SHR]] +// +vuint32m1_t lshr_u32(vuint32m1_t a, vuint32m1_t b) { + return a >> b; +} + +// CHECK-LABEL: @compound_lshr_u32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[SHR:%.*]] = lshr [[A:%.*]], [[B:%.*]] +// CHECK-NEXT: ret [[SHR]] +// +vuint32m1_t compound_lshr_u32(vuint32m1_t a, vuint32m1_t b) { + a >>= b; + return a; +} diff --git a/clang/test/CodeGen/RISCV/rvv-vector-subscript-ops.c b/clang/test/CodeGen/RISCV/rvv-vector-subscript-ops.c new file mode 100644 index 0000000000000..e7174bde980a7 --- /dev/null +++ b/clang/test/CodeGen/RISCV/rvv-vector-subscript-ops.c @@ -0,0 +1,99 @@ +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py +// RUN: %clang_cc1 -triple riscv32 -target-feature +v \ +// RUN: -disable-O0-optnone \ +// RUN: -emit-llvm -o - %s | opt -S -passes=sroa | FileCheck %s \ +// RUN: --check-prefixes=CHECK,CHECK32 +// RUN: %clang_cc1 -triple riscv64 -target-feature +v \ +// RUN: -disable-O0-optnone \ +// RUN: -emit-llvm -o - %s | opt -S -passes=sroa | FileCheck %s \ +// RUN: --check-prefixes=CHECK,CHECK64 + +// REQUIRES: riscv-registered-target + +#include +#include + +// CONSTANT INDEX + +// CHECK-LABEL: @subscript_const_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[VECEXT:%.*]] = extractelement [[A:%.*]], i32 0 +// CHECK-NEXT: ret i32 [[VECEXT]] +// +int subscript_const_i32(vint32m1_t a) { + return a[0]; +} + +// CHECK-LABEL: @subscript_const_store_i32( +// CHECK-NEXT: entry: +// CHECK-NEXT: [[VECINS:%.*]] = insertelement [[A:%.*]], i32 [[VAL:%.*]], i32 1 +// CHECK-NEXT: ret [[VECINS]] +// +vint32m1_t subscript_const_store_i32(vint32m1_t a, int val) { + a[1] = val; + return a; +} + +// VARIABLE INDEX — size_t is i64 on rv64, i32 on rv32 + +// CHECK32-LABEL: @subscript_i32( +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[VECEXT:%.*]] = extractelement [[A:%.*]], i32 [[B:%.*]] +// CHECK32-NEXT: ret i32 [[VECEXT]] +// +// CHECK64-LABEL: @subscript_i32( +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[VECEXT:%.*]] = extractelement [[A:%.*]], i64 [[B:%.*]] +// CHECK64-NEXT: ret i32 [[VECEXT]] +// +int subscript_i32(vint32m1_t a, size_t b) { + return a[b]; +} + +// CHECK32-LABEL: @subscript_f32( +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[VECEXT:%.*]] = extractelement [[A:%.*]], i32 [[B:%.*]] +// CHECK32-NEXT: ret float [[VECEXT]] +// +// CHECK64-LABEL: @subscript_f32( +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[VECEXT:%.*]] = extractelement [[A:%.*]], i64 [[B:%.*]] +// CHECK64-NEXT: ret float [[VECEXT]] +// +float subscript_f32(vfloat32m1_t a, size_t b) { + return a[b]; +} + +// CHECK32-LABEL: @subscript_store_f32( +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[VECINS:%.*]] = insertelement [[A:%.*]], float 1.000000e+00, i32 [[B:%.*]] +// CHECK32-NEXT: ret [[VECINS]] +// +// CHECK64-LABEL: @subscript_store_f32( +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[VECINS:%.*]] = insertelement [[A:%.*]], float 1.000000e+00, i64 [[B:%.*]] +// CHECK64-NEXT: ret [[VECINS]] +// +vfloat32m1_t subscript_store_f32(vfloat32m1_t a, size_t b) { + a[b] = 1.0f; + return a; +} + +// CHECK32-LABEL: @subscript_read_write_f32( +// CHECK32-NEXT: entry: +// CHECK32-NEXT: [[VECEXT:%.*]] = extractelement [[A:%.*]], i32 [[B:%.*]] +// CHECK32-NEXT: [[ADD:%.*]] = fadd float [[VECEXT]], 1.000000e+00 +// CHECK32-NEXT: [[VECINS:%.*]] = insertelement [[A]], float [[ADD]], i32 [[B]] +// CHECK32-NEXT: ret [[VECINS]] +// +// CHECK64-LABEL: @subscript_read_write_f32( +// CHECK64-NEXT: entry: +// CHECK64-NEXT: [[VECEXT:%.*]] = extractelement [[A:%.*]], i64 [[B:%.*]] +// CHECK64-NEXT: [[ADD:%.*]] = fadd float [[VECEXT]], 1.000000e+00 +// CHECK64-NEXT: [[VECINS:%.*]] = insertelement [[A]], float [[ADD]], i64 [[B]] +// CHECK64-NEXT: ret [[VECINS]] +// +vfloat32m1_t subscript_read_write_f32(vfloat32m1_t a, size_t b) { + a[b] += 1.0f; + return a; +} diff --git a/clang/test/Sema/riscv-rvv-vector-arith-ops.c b/clang/test/Sema/riscv-rvv-vector-arith-ops.c new file mode 100644 index 0000000000000..71be91d508259 --- /dev/null +++ b/clang/test/Sema/riscv-rvv-vector-arith-ops.c @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -triple riscv32 -target-feature +v -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple riscv64 -target-feature +v -fsyntax-only -verify %s + +// REQUIRES: riscv-registered-target + +#include + +// Arithmetic on mask types is not allowed +vbool32_t bad_add_bool(vbool32_t a, vbool32_t b) { + return a + b; // expected-error {{invalid operands to binary expression}} +} + +// Bitwise NOT on floats is not allowed +vfloat32m1_t bad_not_f32(vfloat32m1_t a) { + return ~a; // expected-error {{invalid argument type}} +} + +// Remainder on floats is not allowed +vfloat32m1_t bad_rem_f32(vfloat32m1_t a, vfloat32m1_t b) { + return a % b; // expected-error {{invalid operands to binary expression}} +} + +// Shift on floats is not allowed +vfloat32m1_t bad_shl_f32(vfloat32m1_t a, vfloat32m1_t b) { + return a << b; // expected-error {{used type 'vfloat32m1_t'}} +} + +// Bitwise ops on floats are not allowed +vfloat32m1_t bad_and_f32(vfloat32m1_t a, vfloat32m1_t b) { + return a & b; // expected-error {{invalid operands to binary expression}} +} + +// Mismatched vector types +vint32m1_t bad_add_mismatch(vint32m1_t a, vint64m1_t b) { + return a + b; // expected-error {{vector operands do not have the same number of elements}} +} + +// Mismatched LMUL +vint32m1_t bad_add_lmul(vint32m1_t a, vint32m2_t b) { + return a + b; // expected-error {{vector operands do not have the same number of elements}} +} + +// Subscript on bool is not allowed +int bad_subscript_bool(vbool32_t a) { + return a[0]; // expected-error {{subscript of svbool_t is not allowed}} +} + +// Subscript with float index is not allowed +int bad_subscript_float_idx(vint32m1_t a) { + return a[0.f]; // expected-error {{array subscript is not an integer}} +} + +int bad_subscript_double_idx(vint32m1_t a) { + return a[0.]; // expected-error {{array subscript is not an integer}} +} + +// Compound assignment on bools is not allowed +void bad_compound_bool(vbool32_t a, vbool32_t b) { + a += b; // expected-error {{invalid operands to binary expression}} +} + +// Mixed signedness (same element size and LMUL) is not allowed +vint32m1_t bad_add_mixed_sign(vint32m1_t a, vuint32m1_t b) { + return a + b; // expected-error {{cannot convert between vector type 'vuint32m1_t'}} +} + +// Mixed element width (different element count) is not allowed +vint32m1_t bad_add_mixed_width(vint32m1_t a, vuint64m1_t b) { + return a + b; // expected-error {{vector operands do not have the same number of elements}} +} + +// Same element count but different element width (i32m1 + i64m2 are both +// vscale x 2, but i32 vs i64) - this is an RVV-specific case that cannot +// occur with SVE where element count always differs with element width. +vint64m2_t bad_add_same_ec_diff_eltty(vint32m1_t a, vint64m2_t b) { + return a + b; // expected-error {{cannot convert between vector type}} +}