https://github.com/MacDue updated https://github.com/llvm/llvm-project/pull/169165
>From 762fc00b986be492236261d90ab6a72207aba1b8 Mon Sep 17 00:00:00 2001 From: MacDue <[email protected]> Date: Sat, 22 Nov 2025 12:56:29 +0000 Subject: [PATCH 1/3] [clang][Sema] Merge Check[Sizeless]VectorConditionalTypes implementations These two functions are almost identical, except for the handling different vector types, so merging them eliminates some duplication. This also fixes some bugs, as "sizeless" vector code was missing checks for several cases. This meant type checking would crash if: - The LHS or RHS type was void - The LHS or RHS type was a fixed-length vector type - There was not a scalable vector type for the result element count/size These are fixed with this patch and tested in Sema/AArch64/sve-vector-conditional-op.cpp. Fixes #169025 --- .../clang/Basic/DiagnosticSemaKinds.td | 2 + clang/include/clang/Sema/Sema.h | 4 - clang/lib/AST/ASTContext.cpp | 10 +- clang/lib/Sema/SemaExprCXX.cpp | 171 ++++++------------ .../AArch64/sve-vector-conditional-op.cpp | 37 ++++ 5 files changed, 98 insertions(+), 126 deletions(-) create mode 100644 clang/test/Sema/AArch64/sve-vector-conditional-op.cpp diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 3df28f2ef3334..b53d9ebe70587 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -8627,6 +8627,8 @@ def err_conditional_vector_size : Error< def err_conditional_vector_element_size : Error< "vector condition type %0 and result type %1 do not have elements of the " "same size">; +def err_conditional_vector_scalar_type_unsupported : Error< + "scalar type %0 not supported with vector condition type %1">; def err_conditional_vector_has_void : Error< "GNU vector conditional operand cannot be %select{void|a throw expression}0">; def err_conditional_vector_operand_type diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 37598f8530c09..3b69d6f723045 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -8699,10 +8699,6 @@ class Sema final : public SemaBase { ExprResult &RHS, SourceLocation QuestionLoc); - QualType CheckSizelessVectorConditionalTypes(ExprResult &Cond, - ExprResult &LHS, ExprResult &RHS, - SourceLocation QuestionLoc); - //// Determines if a type is trivially relocatable /// according to the C++26 rules. // FIXME: This is in Sema because it requires diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index a8b41ba18fa01..2ce16f8d33caa 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4512,25 +4512,25 @@ QualType ASTContext::getScalableVectorType(QualType EltTy, unsigned NumElts, ElBits, NF, IsSigned) \ if (EltTy->hasIntegerRepresentation() && !EltTy->isBooleanType() && \ EltTy->hasSignedIntegerRepresentation() == IsSigned && \ - EltTySize == ElBits && NumElts == (NumEls * NF) && NumFields == 1) { \ + EltTySize == ElBits && NumElts == NumEls && NumFields == NF) { \ return ScalableVecTyMap[K] = SingletonId; \ } #define SVE_VECTOR_TYPE_FLOAT(Name, MangledName, Id, SingletonId, NumEls, \ ElBits, NF) \ if (EltTy->hasFloatingRepresentation() && !EltTy->isBFloat16Type() && \ - EltTySize == ElBits && NumElts == (NumEls * NF) && NumFields == 1) { \ + EltTySize == ElBits && NumElts == NumEls && NumFields == NF) { \ return ScalableVecTyMap[K] = SingletonId; \ } #define SVE_VECTOR_TYPE_BFLOAT(Name, MangledName, Id, SingletonId, NumEls, \ ElBits, NF) \ if (EltTy->hasFloatingRepresentation() && EltTy->isBFloat16Type() && \ - EltTySize == ElBits && NumElts == (NumEls * NF) && NumFields == 1) { \ + EltTySize == ElBits && NumElts == NumEls && NumFields == NF) { \ return ScalableVecTyMap[K] = SingletonId; \ } #define SVE_VECTOR_TYPE_MFLOAT(Name, MangledName, Id, SingletonId, NumEls, \ ElBits, NF) \ - if (EltTy->isMFloat8Type() && EltTySize == ElBits && \ - NumElts == (NumEls * NF) && NumFields == 1) { \ + if (EltTy->isMFloat8Type() && EltTySize == ElBits && NumElts == NumEls && \ + NumFields == NF) { \ return ScalableVecTyMap[K] = SingletonId; \ } #define SVE_PREDICATE_TYPE_ALL(Name, MangledName, Id, SingletonId, NumEls, NF) \ diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 0fe242dce45e9..a529dc98d6317 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5683,21 +5683,33 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); QualType CondType = Cond.get()->getType(); - const auto *CondVT = CondType->castAs<VectorType>(); - QualType CondElementTy = CondVT->getElementType(); - unsigned CondElementCount = CondVT->getNumElements(); QualType LHSType = LHS.get()->getType(); - const auto *LHSVT = LHSType->getAs<VectorType>(); QualType RHSType = RHS.get()->getType(); - const auto *RHSVT = RHSType->getAs<VectorType>(); - QualType ResultType; + bool LHSIsVector = LHSType->isVectorType() || LHSType->isSizelessVectorType(); + bool RHSIsVector = RHSType->isVectorType() || RHSType->isSizelessVectorType(); + + auto GetVectorInfo = + [&](QualType Type) -> std::pair<QualType, llvm::ElementCount> { + QualType ElementTy; + llvm::ElementCount EC; + if (const auto *VT = Type->getAs<VectorType>()) { + ElementTy = VT->getElementType(); + EC = llvm::ElementCount::getFixed(VT->getNumElements()); + } else { + ElementTy = Type->getSizelessVectorEltType(Context); + EC = Context.getBuiltinVectorTypeInfo(Type->castAs<BuiltinType>()).EC; + } + return std::make_pair(ElementTy, EC); + }; + auto [CondElementTy, CondElementCount] = GetVectorInfo(CondType); - if (LHSVT && RHSVT) { - if (isa<ExtVectorType>(CondVT) != isa<ExtVectorType>(LHSVT)) { + QualType ResultType; + if (LHSIsVector && RHSIsVector) { + if (isa<ExtVectorType>(CondType) != isa<ExtVectorType>(LHSType)) { Diag(QuestionLoc, diag::err_conditional_vector_cond_result_mismatch) - << /*isExtVector*/ isa<ExtVectorType>(CondVT); + << /*isExtVector*/ isa<ExtVectorType>(CondType); return {}; } @@ -5708,12 +5720,17 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, return {}; } ResultType = Context.getCommonSugaredType(LHSType, RHSType); - } else if (LHSVT || RHSVT) { - ResultType = CheckVectorOperands( - LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true, - /*AllowBoolConversions*/ false, - /*AllowBoolOperation*/ true, - /*ReportInvalid*/ true); + } else if (LHSIsVector || RHSIsVector) { + if (CondType->isSizelessVectorType()) + ResultType = CheckSizelessVectorOperands(LHS, RHS, QuestionLoc, + /*IsCompAssign*/ false, + ArithConvKind::Conditional); + else + ResultType = CheckVectorOperands( + LHS, RHS, QuestionLoc, /*isCompAssign*/ false, /*AllowBothBool*/ true, + /*AllowBoolConversions*/ false, + /*AllowBoolOperation*/ true, + /*ReportInvalid*/ true); if (ResultType.isNull()) return {}; } else { @@ -5731,24 +5748,33 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, << ResultElementTy; return {}; } - if (CondType->isExtVectorType()) - ResultType = - Context.getExtVectorType(ResultElementTy, CondVT->getNumElements()); - else - ResultType = Context.getVectorType( - ResultElementTy, CondVT->getNumElements(), VectorKind::Generic); - + if (CondType->isExtVectorType()) { + ResultType = Context.getExtVectorType(ResultElementTy, + CondElementCount.getFixedValue()); + } else if (CondType->isSizelessVectorType()) { + ResultType = Context.getScalableVectorType( + ResultElementTy, CondElementCount.getKnownMinValue()); + // There are not scalable vector type mappings for all element counts. + if (ResultType.isNull()) { + Diag(QuestionLoc, diag::err_conditional_vector_scalar_type_unsupported) + << ResultElementTy << CondType; + return {}; + } + } else { + ResultType = Context.getVectorType(ResultElementTy, + CondElementCount.getFixedValue(), + VectorKind::Generic); + } LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat); RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat); } - assert(!ResultType.isNull() && ResultType->isVectorType() && + assert(!ResultType.isNull() && + (ResultType->isVectorType() || ResultType->isSizelessVectorType()) && (!CondType->isExtVectorType() || ResultType->isExtVectorType()) && "Result should have been a vector type"); - auto *ResultVectorTy = ResultType->castAs<VectorType>(); - QualType ResultElementTy = ResultVectorTy->getElementType(); - unsigned ResultElementCount = ResultVectorTy->getNumElements(); + auto [ResultElementTy, ResultElementCount] = GetVectorInfo(ResultType); if (ResultElementCount != CondElementCount) { Diag(QuestionLoc, diag::err_conditional_vector_size) << CondType << ResultType; @@ -5767,90 +5793,6 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, return ResultType; } -QualType Sema::CheckSizelessVectorConditionalTypes(ExprResult &Cond, - ExprResult &LHS, - ExprResult &RHS, - SourceLocation QuestionLoc) { - LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); - RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); - - QualType CondType = Cond.get()->getType(); - const auto *CondBT = CondType->castAs<BuiltinType>(); - QualType CondElementTy = CondBT->getSveEltType(Context); - llvm::ElementCount CondElementCount = - Context.getBuiltinVectorTypeInfo(CondBT).EC; - - QualType LHSType = LHS.get()->getType(); - const auto *LHSBT = - LHSType->isSveVLSBuiltinType() ? LHSType->getAs<BuiltinType>() : nullptr; - QualType RHSType = RHS.get()->getType(); - const auto *RHSBT = - RHSType->isSveVLSBuiltinType() ? RHSType->getAs<BuiltinType>() : nullptr; - - QualType ResultType; - - if (LHSBT && RHSBT) { - // If both are sizeless vector types, they must be the same type. - if (!Context.hasSameType(LHSType, RHSType)) { - Diag(QuestionLoc, diag::err_conditional_vector_mismatched) - << LHSType << RHSType; - return QualType(); - } - ResultType = LHSType; - } else if (LHSBT || RHSBT) { - ResultType = CheckSizelessVectorOperands(LHS, RHS, QuestionLoc, - /*IsCompAssign*/ false, - ArithConvKind::Conditional); - if (ResultType.isNull()) - return QualType(); - } else { - // Both are scalar so splat - QualType ResultElementTy; - LHSType = LHSType.getCanonicalType().getUnqualifiedType(); - RHSType = RHSType.getCanonicalType().getUnqualifiedType(); - - if (Context.hasSameType(LHSType, RHSType)) - ResultElementTy = LHSType; - else - ResultElementTy = UsualArithmeticConversions(LHS, RHS, QuestionLoc, - ArithConvKind::Conditional); - - if (ResultElementTy->isEnumeralType()) { - Diag(QuestionLoc, diag::err_conditional_vector_operand_type) - << ResultElementTy; - return QualType(); - } - - ResultType = Context.getScalableVectorType( - ResultElementTy, CondElementCount.getKnownMinValue()); - - LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat); - RHS = ImpCastExprToType(RHS.get(), ResultType, CK_VectorSplat); - } - - assert(!ResultType.isNull() && ResultType->isSveVLSBuiltinType() && - "Result should have been a vector type"); - auto *ResultBuiltinTy = ResultType->castAs<BuiltinType>(); - QualType ResultElementTy = ResultBuiltinTy->getSveEltType(Context); - llvm::ElementCount ResultElementCount = - Context.getBuiltinVectorTypeInfo(ResultBuiltinTy).EC; - - if (ResultElementCount != CondElementCount) { - Diag(QuestionLoc, diag::err_conditional_vector_size) - << CondType << ResultType; - return QualType(); - } - - if (Context.getTypeSize(ResultElementTy) != - Context.getTypeSize(CondElementTy)) { - Diag(QuestionLoc, diag::err_conditional_vector_element_size) - << CondType << ResultType; - return QualType(); - } - - return ResultType; -} - QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, ExprValueKind &VK, ExprObjectKind &OK, @@ -5862,16 +5804,14 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, VK = VK_PRValue; OK = OK_Ordinary; bool IsVectorConditional = - isValidVectorForConditionalCondition(Context, Cond.get()->getType()); - - bool IsSizelessVectorConditional = + isValidVectorForConditionalCondition(Context, Cond.get()->getType()) || isValidSizelessVectorForConditionalCondition(Context, Cond.get()->getType()); // C++11 [expr.cond]p1 // The first expression is contextually converted to bool. if (!Cond.get()->isTypeDependent()) { - ExprResult CondRes = IsVectorConditional || IsSizelessVectorConditional + ExprResult CondRes = IsVectorConditional ? DefaultFunctionArrayLvalueConversion(Cond.get()) : CheckCXXBooleanCondition(Cond.get()); if (CondRes.isInvalid()) @@ -5940,9 +5880,6 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (IsVectorConditional) return CheckVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc); - if (IsSizelessVectorConditional) - return CheckSizelessVectorConditionalTypes(Cond, LHS, RHS, QuestionLoc); - // WebAssembly tables are not allowed as conditional LHS or RHS. if (LTy->isWebAssemblyTableType() || RTy->isWebAssemblyTableType()) { Diag(QuestionLoc, diag::err_wasm_table_conditional_expression) diff --git a/clang/test/Sema/AArch64/sve-vector-conditional-op.cpp b/clang/test/Sema/AArch64/sve-vector-conditional-op.cpp new file mode 100644 index 0000000000000..0ca55e6268658 --- /dev/null +++ b/clang/test/Sema/AArch64/sve-vector-conditional-op.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 %s -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sve -verify + +typedef int fixed_vector __attribute__((vector_size(4))); + +auto error_fixed_vector_result(__SVBool_t svbool, fixed_vector a, fixed_vector b) { + // expected-error@+1 {{vector condition type '__SVBool_t' and result type 'fixed_vector' (vector of 1 'int' value) do not have the same number of elements}} + return svbool ? a : b; +} + +auto error_void_result(__SVBool_t svbool) { + // expected-error@+1 {{GNU vector conditional operand cannot be void}} + return svbool ? (void)0 : (void)1; +} + +auto error_sve_splat_result_unsupported(__SVBool_t svbool, long long a, long long b) { + // expected-error@+1 {{scalar type 'long long' not supported with vector condition type '__SVBool_t'}} + return svbool ? a : b; +} + +auto error_sve_vector_result_matched_element_count(__SVBool_t svbool, __SVUint32_t a, __SVUint32_t b) { + // expected-error@+1 {{vector condition type '__SVBool_t' and result type '__SVUint32_t' do not have the same number of elements}} + return svbool ? a : b; +} + +// The following cases should be supported: + +__SVBool_t cond_svbool(__SVBool_t a, __SVBool_t b) { + return a < b ? a : b; +} + +__SVFloat32_t cond_svf32(__SVFloat32_t a, __SVFloat32_t b) { + return a < b ? a : b; +} + +__SVUint64_t cond_u64_splat(__SVUint64_t a) { + return a < 1ul ? a : 1ul; +} >From 354e037656b41c90bae9971805e251b2b9df9689 Mon Sep 17 00:00:00 2001 From: MacDue <[email protected]> Date: Sat, 22 Nov 2025 14:43:58 +0000 Subject: [PATCH 2/3] Tweak --- clang/lib/AST/ASTContext.cpp | 10 +++++----- clang/lib/Sema/SemaExprCXX.cpp | 6 ++++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 2ce16f8d33caa..a8b41ba18fa01 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4512,25 +4512,25 @@ QualType ASTContext::getScalableVectorType(QualType EltTy, unsigned NumElts, ElBits, NF, IsSigned) \ if (EltTy->hasIntegerRepresentation() && !EltTy->isBooleanType() && \ EltTy->hasSignedIntegerRepresentation() == IsSigned && \ - EltTySize == ElBits && NumElts == NumEls && NumFields == NF) { \ + EltTySize == ElBits && NumElts == (NumEls * NF) && NumFields == 1) { \ return ScalableVecTyMap[K] = SingletonId; \ } #define SVE_VECTOR_TYPE_FLOAT(Name, MangledName, Id, SingletonId, NumEls, \ ElBits, NF) \ if (EltTy->hasFloatingRepresentation() && !EltTy->isBFloat16Type() && \ - EltTySize == ElBits && NumElts == NumEls && NumFields == NF) { \ + EltTySize == ElBits && NumElts == (NumEls * NF) && NumFields == 1) { \ return ScalableVecTyMap[K] = SingletonId; \ } #define SVE_VECTOR_TYPE_BFLOAT(Name, MangledName, Id, SingletonId, NumEls, \ ElBits, NF) \ if (EltTy->hasFloatingRepresentation() && EltTy->isBFloat16Type() && \ - EltTySize == ElBits && NumElts == NumEls && NumFields == NF) { \ + EltTySize == ElBits && NumElts == (NumEls * NF) && NumFields == 1) { \ return ScalableVecTyMap[K] = SingletonId; \ } #define SVE_VECTOR_TYPE_MFLOAT(Name, MangledName, Id, SingletonId, NumEls, \ ElBits, NF) \ - if (EltTy->isMFloat8Type() && EltTySize == ElBits && NumElts == NumEls && \ - NumFields == NF) { \ + if (EltTy->isMFloat8Type() && EltTySize == ElBits && \ + NumElts == (NumEls * NF) && NumFields == 1) { \ return ScalableVecTyMap[K] = SingletonId; \ } #define SVE_PREDICATE_TYPE_ALL(Name, MangledName, Id, SingletonId, NumEls, NF) \ diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index a529dc98d6317..96b92dff81bf5 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5697,8 +5697,10 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, ElementTy = VT->getElementType(); EC = llvm::ElementCount::getFixed(VT->getNumElements()); } else { - ElementTy = Type->getSizelessVectorEltType(Context); - EC = Context.getBuiltinVectorTypeInfo(Type->castAs<BuiltinType>()).EC; + ASTContext::BuiltinVectorTypeInfo VectorInfo = + Context.getBuiltinVectorTypeInfo(Type->castAs<BuiltinType>()); + ElementTy = VectorInfo.ElementType; + EC = VectorInfo.EC; } return std::make_pair(ElementTy, EC); }; >From 6e12cfa2be71045a561dd9c1ed27002e5df2f923 Mon Sep 17 00:00:00 2001 From: MacDue <[email protected]> Date: Sat, 22 Nov 2025 15:01:53 +0000 Subject: [PATCH 3/3] Tweak --- clang/lib/Sema/SemaExprCXX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 96b92dff81bf5..57bce1781617c 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -5709,7 +5709,7 @@ QualType Sema::CheckVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, QualType ResultType; if (LHSIsVector && RHSIsVector) { - if (isa<ExtVectorType>(CondType) != isa<ExtVectorType>(LHSType)) { + if (CondType->isExtVectorType() != LHSType->isExtVectorType()) { Diag(QuestionLoc, diag::err_conditional_vector_cond_result_mismatch) << /*isExtVector*/ isa<ExtVectorType>(CondType); return {}; _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
