diff options
Diffstat (limited to 'clang/lib/Sema')
-rw-r--r-- | clang/lib/Sema/DeclSpec.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 80 | ||||
-rw-r--r-- | clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h | 2 | ||||
-rw-r--r-- | clang/lib/Sema/HLSLExternalSemaSource.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Sema/SemaCast.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaConcept.cpp | 50 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 136 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 114 | ||||
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 14 | ||||
-rw-r--r-- | clang/lib/Sema/SemaHLSL.cpp | 18 | ||||
-rw-r--r-- | clang/lib/Sema/SemaRISCV.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 114 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 40 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 10 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 49 |
16 files changed, 576 insertions, 78 deletions
diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 184d31e..9da3d0d 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -1369,7 +1369,8 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { if (S.getLangOpts().C23 && getConstexprSpecifier() == ConstexprSpecKind::Constexpr && - StorageClassSpec == SCS_extern) { + getTypeSpecType() != TST_unspecified && + (StorageClassSpec == SCS_extern || StorageClassSpec == SCS_auto)) { S.Diag(ConstexprLoc, diag::err_invalid_decl_spec_combination) << DeclSpec::getSpecifierName(getStorageClassSpec()) << SourceRange(getStorageClassSpecLoc()); diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 40c318a..066acf6 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -57,6 +57,29 @@ CXXConstructorDecl *lookupCopyConstructor(QualType ResTy) { return CD; return nullptr; } + +ParameterABI +convertParamModifierToParamABI(HLSLParamModifierAttr::Spelling Modifier) { + assert(Modifier != HLSLParamModifierAttr::Spelling::Keyword_in && + "HLSL 'in' parameters modifier cannot be converted to ParameterABI"); + switch (Modifier) { + case HLSLParamModifierAttr::Spelling::Keyword_out: + return ParameterABI::HLSLOut; + case HLSLParamModifierAttr::Spelling::Keyword_inout: + return ParameterABI::HLSLInOut; + default: + llvm_unreachable("Invalid HLSL parameter modifier"); + } +} + +QualType getInoutParameterType(ASTContext &AST, QualType Ty) { + assert(!Ty->isReferenceType() && + "Pointer and reference types cannot be inout or out parameters"); + Ty = AST.getLValueReferenceType(Ty); + Ty.addRestrict(); + return Ty; +} + } // namespace // Builder for template arguments of builtin types. Used internally @@ -430,19 +453,36 @@ BuiltinTypeMethodBuilder::addParam(StringRef Name, QualType Ty, void BuiltinTypeMethodBuilder::createDecl() { assert(Method == nullptr && "Method or constructor is already created"); - // create method or constructor type + // create function prototype ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); SmallVector<QualType> ParamTypes; - for (Param &MP : Params) + SmallVector<FunctionType::ExtParameterInfo> ParamExtInfos(Params.size()); + uint32_t ArgIndex = 0; + + // Create function prototype. + bool UseParamExtInfo = false; + for (Param &MP : Params) { + if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) { + UseParamExtInfo = true; + FunctionType::ExtParameterInfo &PI = ParamExtInfos[ArgIndex]; + ParamExtInfos[ArgIndex] = + PI.withABI(convertParamModifierToParamABI(MP.Modifier)); + if (!MP.Ty->isDependentType()) + MP.Ty = getInoutParameterType(AST, MP.Ty); + } ParamTypes.emplace_back(MP.Ty); + ++ArgIndex; + } FunctionProtoType::ExtProtoInfo ExtInfo; + if (UseParamExtInfo) + ExtInfo.ExtParameterInfos = ParamExtInfos.data(); if (IsConst) ExtInfo.TypeQuals.addConst(); QualType FuncTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo); - // create method or constructor decl + // Create method or constructor declaration. auto *TSInfo = AST.getTrivialTypeSourceInfo(FuncTy, SourceLocation()); DeclarationNameInfo NameInfo = DeclarationNameInfo(Name, SourceLocation()); if (IsCtor) @@ -455,7 +495,7 @@ void BuiltinTypeMethodBuilder::createDecl() { AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, SC, false, false, ConstexprSpecKind::Unspecified, SourceLocation()); - // create params & set them to the function prototype + // Create params & set them to the method/constructor and function prototype. SmallVector<ParmVarDecl *> ParmDecls; unsigned CurScopeDepth = DeclBuilder.SemaRef.getCurScope()->getDepth(); auto FnProtoLoc = @@ -1258,5 +1298,37 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() { .finalize(); } +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addGetDimensionsMethodForBuffer() { + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + ASTContext &AST = SemaRef.getASTContext(); + QualType UIntTy = AST.UnsignedIntTy; + + QualType HandleTy = getResourceHandleField()->getType(); + auto *AttrResTy = cast<HLSLAttributedResourceType>(HandleTy.getTypePtr()); + + // Structured buffers except {RW}ByteAddressBuffer have overload + // GetDimensions(out uint numStructs, out uint stride). + if (AttrResTy->getAttrs().RawBuffer && + AttrResTy->getContainedType() != AST.Char8Ty) { + return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy) + .addParam("numStructs", UIntTy, HLSLParamModifierAttr::Keyword_out) + .addParam("stride", UIntTy, HLSLParamModifierAttr::Keyword_out) + .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(), + PH::Handle, PH::_0) + .callBuiltin("__builtin_hlsl_resource_getstride", QualType(), + PH::Handle, PH::_1) + .finalize(); + } + + // Typed buffers and {RW}ByteAddressBuffer have overload + // GetDimensions(out uint dim). + return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy) + .addParam("dim", UIntTy, HLSLParamModifierAttr::Keyword_out) + .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(), + PH::Handle, PH::_0) + .finalize(); +} + } // namespace hlsl } // namespace clang diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h index 86cbd10..95e3a6c 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h @@ -94,6 +94,8 @@ public: BuiltinTypeDeclBuilder &addAppendMethod(); BuiltinTypeDeclBuilder &addConsumeMethod(); + BuiltinTypeDeclBuilder &addGetDimensionsMethodForBuffer(); + private: BuiltinTypeDeclBuilder &addCreateFromBinding(); BuiltinTypeDeclBuilder &addCreateFromImplicitBinding(); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index e118dda..6be84f1 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -159,7 +159,8 @@ void HLSLExternalSemaSource::defineHLSLMatrixAlias() { SourceLocation(), ColsParam)); TemplateParams.emplace_back(ColsParam); - const unsigned MaxMatDim = 4; + const unsigned MaxMatDim = SemaPtr->getLangOpts().MaxMatrixDimension; + auto *MaxRow = IntegerLiteral::Create( AST, llvm::APInt(AST.getIntWidth(AST.IntTy), MaxMatDim), AST.IntTy, SourceLocation()); @@ -379,6 +380,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/false, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -391,6 +393,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/false, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -403,6 +406,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/false, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -414,6 +418,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { /*RawBuffer=*/true, /*HasCounter=*/false) .addArraySubscriptOperators() .addLoadMethods() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -427,6 +432,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { .addLoadMethods() .addIncrementCounterMethod() .addDecrementCounterMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -438,6 +444,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/true) .addAppendMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -449,6 +456,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/true) .addConsumeMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -463,6 +471,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { .addLoadMethods() .addIncrementCounterMethod() .addDecrementCounterMethod() + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); @@ -471,6 +480,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::SRV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/false) + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWByteAddressBuffer") @@ -478,6 +488,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/false, /*RawBuffer=*/true, /*HasCounter=*/false) + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, @@ -486,6 +497,7 @@ void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() { onCompletion(Decl, [this](CXXRecordDecl *Decl) { setupBufferType(Decl, *SemaPtr, ResourceClass::UAV, /*IsROV=*/true, /*RawBuffer=*/true, /*HasCounter=*/false) + .addGetDimensionsMethodForBuffer() .completeDefinition(); }); } diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index ddf17d8..5360f8a 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -2927,6 +2927,8 @@ bool CastOperation::CheckHLSLCStyleCast(CheckedConversionKind CCK) { SrcExpr = Self.ImpCastExprToType( SrcExpr.get(), Self.Context.getArrayParameterType(SrcTy), CK_HLSLArrayRValue, VK_PRValue, nullptr, CCK); + else + SrcExpr = Self.DefaultLvalueConversion(SrcExpr.get()); Kind = CK_HLSLElementwiseCast; return true; } @@ -2935,6 +2937,7 @@ bool CastOperation::CheckHLSLCStyleCast(CheckedConversionKind CCK) { // If the relative order of this and the HLSLElementWise cast checks // are changed, it might change which cast handles what in a few cases if (Self.HLSL().CanPerformAggregateSplatCast(SrcExpr.get(), DestType)) { + SrcExpr = Self.DefaultLvalueConversion(SrcExpr.get()); const VectorType *VT = SrcTy->getAs<VectorType>(); // change splat from vec1 case to splat from scalar if (VT && VT->getNumElements() == 1) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 4f409ca..652527a 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -16239,9 +16239,9 @@ getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) { return {}; } uint64_t Dim = Value->getZExtValue(); - if (!ConstantMatrixType::isDimensionValid(Dim)) { + if (Dim == 0 || Dim > S.Context.getLangOpts().MaxMatrixDimension) { S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_invalid_dimension) - << Name << ConstantMatrixType::getMaxElementsPerDimension(); + << Name << S.Context.getLangOpts().MaxMatrixDimension; return {}; } return Dim; diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 87dd682..04a73181 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -1217,13 +1217,51 @@ bool Sema::CheckConstraintSatisfaction( return false; } +static const ExprResult +SubstituteConceptsInConstrainExpression(Sema &S, const NamedDecl *D, + const ConceptSpecializationExpr *CSE, + UnsignedOrNone SubstIndex) { + + // [C++2c] [temp.constr.normal] + // Otherwise, to form CE, any non-dependent concept template argument Ai + // is substituted into the constraint-expression of C. + // If any such substitution results in an invalid concept-id, + // the program is ill-formed; no diagnostic is required. + + ConceptDecl *Concept = CSE->getNamedConcept()->getCanonicalDecl(); + Sema::ArgPackSubstIndexRAII _(S, SubstIndex); + + const ASTTemplateArgumentListInfo *ArgsAsWritten = + CSE->getTemplateArgsAsWritten(); + if (llvm::none_of( + ArgsAsWritten->arguments(), [&](const TemplateArgumentLoc &ArgLoc) { + return !ArgLoc.getArgument().isDependent() && + ArgLoc.getArgument().isConceptOrConceptTemplateParameter(); + })) { + return Concept->getConstraintExpr(); + } + + MultiLevelTemplateArgumentList MLTAL = S.getTemplateInstantiationArgs( + Concept, Concept->getLexicalDeclContext(), + /*Final=*/false, CSE->getTemplateArguments(), + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); + return S.SubstConceptTemplateArguments(CSE, Concept->getConstraintExpr(), + MLTAL); +} + bool Sema::CheckConstraintSatisfaction( const ConceptSpecializationExpr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { + ExprResult Res = SubstituteConceptsInConstrainExpression( + *this, nullptr, ConstraintExpr, ArgPackSubstIndex); + if (!Res.isUsable()) + return true; + llvm::SmallVector<AssociatedConstraint, 1> Constraints; - Constraints.emplace_back( - ConstraintExpr->getNamedConcept()->getConstraintExpr()); + Constraints.emplace_back(Res.get()); MultiLevelTemplateArgumentList MLTAL(ConstraintExpr->getNamedConcept(), ConstraintExpr->getTemplateArguments(), @@ -2249,8 +2287,14 @@ NormalizedConstraint *NormalizedConstraint::fromConstraintExpr( // Use canonical declarations to merge ConceptDecls across // different modules. ConceptDecl *CD = CSE->getNamedConcept()->getCanonicalDecl(); + + ExprResult Res = + SubstituteConceptsInConstrainExpression(S, D, CSE, SubstIndex); + if (!Res.isUsable()) + return nullptr; + SubNF = NormalizedConstraint::fromAssociatedConstraints( - S, CD, AssociatedConstraint(CD->getConstraintExpr(), SubstIndex)); + S, CD, AssociatedConstraint(Res.get(), SubstIndex)); if (!SubNF) return nullptr; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 04d46d6..fc3aabf 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7640,6 +7640,58 @@ static bool isMainVar(DeclarationName Name, VarDecl *VD) { VD->isExternC()); } +void Sema::CheckAsmLabel(Scope *S, Expr *E, StorageClass SC, + TypeSourceInfo *TInfo, VarDecl *NewVD) { + + // Quickly return if the function does not have an `asm` attribute. + if (E == nullptr) + return; + + // The parser guarantees this is a string. + StringLiteral *SE = cast<StringLiteral>(E); + StringRef Label = SE->getString(); + QualType R = TInfo->getType(); + if (S->getFnParent() != nullptr) { + switch (SC) { + case SC_None: + case SC_Auto: + Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; + break; + case SC_Register: + // Local Named register + if (!Context.getTargetInfo().isValidGCCRegisterName(Label) && + DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) + Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; + break; + case SC_Static: + case SC_Extern: + case SC_PrivateExtern: + break; + } + } else if (SC == SC_Register) { + // Global Named register + if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) { + const auto &TI = Context.getTargetInfo(); + bool HasSizeMismatch; + + if (!TI.isValidGCCRegisterName(Label)) + Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; + else if (!TI.validateGlobalRegisterVariable(Label, Context.getTypeSize(R), + HasSizeMismatch)) + Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label; + else if (HasSizeMismatch) + Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label; + } + + if (!R->isIntegralType(Context) && !R->isPointerType()) { + Diag(TInfo->getTypeLoc().getBeginLoc(), + diag::err_asm_unsupported_register_type) + << TInfo->getTypeLoc().getSourceRange(); + NewVD->setInvalidDecl(true); + } + } +} + NamedDecl *Sema::ActOnVariableDeclarator( Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, @@ -8124,6 +8176,26 @@ NamedDecl *Sema::ActOnVariableDeclarator( } } + if (Expr *E = D.getAsmLabel()) { + // The parser guarantees this is a string. + StringLiteral *SE = cast<StringLiteral>(E); + StringRef Label = SE->getString(); + + // Insert the asm attribute. + NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0))); + } else if (!ExtnameUndeclaredIdentifiers.empty()) { + llvm::DenseMap<IdentifierInfo *, AsmLabelAttr *>::iterator I = + ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); + if (I != ExtnameUndeclaredIdentifiers.end()) { + if (isDeclExternC(NewVD)) { + NewVD->addAttr(I->second); + ExtnameUndeclaredIdentifiers.erase(I); + } else + Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied) + << /*Variable*/ 1 << NewVD; + } + } + // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); @@ -8174,65 +8246,11 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (getLangOpts().ObjCAutoRefCount && ObjC().inferObjCARCLifetime(NewVD)) NewVD->setInvalidDecl(); - // Handle GNU asm-label extension (encoded as an attribute). - if (Expr *E = D.getAsmLabel()) { - // The parser guarantees this is a string. - StringLiteral *SE = cast<StringLiteral>(E); - StringRef Label = SE->getString(); - if (S->getFnParent() != nullptr) { - switch (SC) { - case SC_None: - case SC_Auto: - Diag(E->getExprLoc(), diag::warn_asm_label_on_auto_decl) << Label; - break; - case SC_Register: - // Local Named register - if (!Context.getTargetInfo().isValidGCCRegisterName(Label) && - DeclAttrsMatchCUDAMode(getLangOpts(), getCurFunctionDecl())) - Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; - break; - case SC_Static: - case SC_Extern: - case SC_PrivateExtern: - break; - } - } else if (SC == SC_Register) { - // Global Named register - if (DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) { - const auto &TI = Context.getTargetInfo(); - bool HasSizeMismatch; - - if (!TI.isValidGCCRegisterName(Label)) - Diag(E->getExprLoc(), diag::err_asm_unknown_register_name) << Label; - else if (!TI.validateGlobalRegisterVariable(Label, - Context.getTypeSize(R), - HasSizeMismatch)) - Diag(E->getExprLoc(), diag::err_asm_invalid_global_var_reg) << Label; - else if (HasSizeMismatch) - Diag(E->getExprLoc(), diag::err_asm_register_size_mismatch) << Label; - } - - if (!R->isIntegralType(Context) && !R->isPointerType()) { - Diag(TInfo->getTypeLoc().getBeginLoc(), - diag::err_asm_unsupported_register_type) - << TInfo->getTypeLoc().getSourceRange(); - NewVD->setInvalidDecl(true); - } - } - - NewVD->addAttr(AsmLabelAttr::Create(Context, Label, SE->getStrTokenLoc(0))); - } else if (!ExtnameUndeclaredIdentifiers.empty()) { - llvm::DenseMap<IdentifierInfo*,AsmLabelAttr*>::iterator I = - ExtnameUndeclaredIdentifiers.find(NewVD->getIdentifier()); - if (I != ExtnameUndeclaredIdentifiers.end()) { - if (isDeclExternC(NewVD)) { - NewVD->addAttr(I->second); - ExtnameUndeclaredIdentifiers.erase(I); - } else - Diag(NewVD->getLocation(), diag::warn_redefine_extname_not_applied) - << /*Variable*/1 << NewVD; - } - } + // Check the ASM label here, as we need to know all other attributes of the + // Decl first. Otherwise, we can't know if the asm label refers to the + // host or device in a CUDA context. The device has other registers than + // host and we must know where the function will be placed. + CheckAsmLabel(S, D.getAsmLabel(), SC, TInfo, NewVD); // Find the shadowed declaration before filtering for scope. NamedDecl *ShadowedDecl = D.getCXXScopeSpec().isEmpty() diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index e6f8748..9475b8a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -5676,6 +5676,114 @@ static void handleLaunchBoundsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { AL.getNumArgs() > 2 ? AL.getArgAsExpr(2) : nullptr); } +static std::pair<Expr *, int> +makeClusterDimsArgExpr(Sema &S, Expr *E, const CUDAClusterDimsAttr &AL, + const unsigned Idx) { + if (!E || S.DiagnoseUnexpandedParameterPack(E)) + return {}; + + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (E->isInstantiationDependent()) + return {E, 1}; + + std::optional<llvm::APSInt> I = E->getIntegerConstantExpr(S.Context); + if (!I) { + S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) + << &AL << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); + return {}; + } + // Make sure we can fit it in 4 bits. + if (!I->isIntN(4)) { + S.Diag(E->getExprLoc(), diag::err_ice_too_large) + << toString(*I, 10, false) << 4 << /*Unsigned=*/1; + return {}; + } + if (*I < 0) { + S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative) + << &AL << Idx << E->getSourceRange(); + } + + return {ConstantExpr::Create(S.getASTContext(), E, APValue(*I)), + I->getZExtValue()}; +} + +CUDAClusterDimsAttr *Sema::createClusterDimsAttr(const AttributeCommonInfo &CI, + Expr *X, Expr *Y, Expr *Z) { + CUDAClusterDimsAttr TmpAttr(Context, CI, X, Y, Z); + + auto [NewX, ValX] = makeClusterDimsArgExpr(*this, X, TmpAttr, /*Idx=*/0); + auto [NewY, ValY] = makeClusterDimsArgExpr(*this, Y, TmpAttr, /*Idx=*/1); + auto [NewZ, ValZ] = makeClusterDimsArgExpr(*this, Z, TmpAttr, /*Idx=*/2); + + if (!NewX || (Y && !NewY) || (Z && !NewZ)) + return nullptr; + + int FlatDim = ValX * ValY * ValZ; + const llvm::Triple TT = + (!Context.getLangOpts().CUDAIsDevice && Context.getAuxTargetInfo()) + ? Context.getAuxTargetInfo()->getTriple() + : Context.getTargetInfo().getTriple(); + int MaxDim = 1; + if (TT.isNVPTX()) + MaxDim = 8; + else if (TT.isAMDGPU()) + MaxDim = 16; + else + return nullptr; + + // A maximum of 8 thread blocks in a cluster is supported as a portable + // cluster size in CUDA. The number is 16 for AMDGPU. + if (FlatDim > MaxDim) { + Diag(CI.getLoc(), diag::err_cluster_dims_too_large) << MaxDim << FlatDim; + return nullptr; + } + + return CUDAClusterDimsAttr::Create(Context, NewX, NewY, NewZ, CI); +} + +void Sema::addClusterDimsAttr(Decl *D, const AttributeCommonInfo &CI, Expr *X, + Expr *Y, Expr *Z) { + if (auto *Attr = createClusterDimsAttr(CI, X, Y, Z)) + D->addAttr(Attr); +} + +void Sema::addNoClusterAttr(Decl *D, const AttributeCommonInfo &CI) { + D->addAttr(CUDANoClusterAttr::Create(Context, CI)); +} + +static void handleClusterDimsAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const TargetInfo &TTI = S.Context.getTargetInfo(); + OffloadArch Arch = StringToOffloadArch(TTI.getTargetOpts().CPU); + if ((TTI.getTriple().isNVPTX() && Arch < clang::OffloadArch::SM_90) || + (TTI.getTriple().isAMDGPU() && + !TTI.hasFeatureEnabled(TTI.getTargetOpts().FeatureMap, "clusters"))) { + S.Diag(AL.getLoc(), diag::err_cluster_attr_not_supported) << AL; + return; + } + + if (!AL.checkAtLeastNumArgs(S, /*Num=*/1) || + !AL.checkAtMostNumArgs(S, /*Num=*/3)) + return; + + S.addClusterDimsAttr(D, AL, AL.getArgAsExpr(0), + AL.getNumArgs() > 1 ? AL.getArgAsExpr(1) : nullptr, + AL.getNumArgs() > 2 ? AL.getArgAsExpr(2) : nullptr); +} + +static void handleNoClusterAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + const TargetInfo &TTI = S.Context.getTargetInfo(); + OffloadArch Arch = StringToOffloadArch(TTI.getTargetOpts().CPU); + if ((TTI.getTriple().isNVPTX() && Arch < clang::OffloadArch::SM_90) || + (TTI.getTriple().isAMDGPU() && + !TTI.hasFeatureEnabled(TTI.getTargetOpts().FeatureMap, "clusters"))) { + S.Diag(AL.getLoc(), diag::err_cluster_attr_not_supported) << AL; + return; + } + + S.addNoClusterAttr(D, AL); +} + static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { @@ -7141,6 +7249,12 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, case ParsedAttr::AT_CUDALaunchBounds: handleLaunchBoundsAttr(S, D, AL); break; + case ParsedAttr::AT_CUDAClusterDims: + handleClusterDimsAttr(S, D, AL); + break; + case ParsedAttr::AT_CUDANoCluster: + handleNoClusterAttr(S, D, AL); + break; case ParsedAttr::AT_Restrict: handleRestrictAttr(S, D, AL); break; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 3e0e9bb..dca9d6e 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15944,6 +15944,20 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } + } else if (Context.getLangOpts().HLSL && resultType->isVectorType() && + !resultType->hasBooleanRepresentation()) { + // HLSL unary logical 'not' behaves like C++, which states that the + // operand is converted to bool and the result is bool, however HLSL + // extends this property to vectors. + const VectorType *VTy = resultType->castAs<VectorType>(); + resultType = + Context.getExtVectorType(Context.BoolTy, VTy->getNumElements()); + + Input = ImpCastExprToType( + Input.get(), resultType, + ScalarTypeToBooleanCastKind(VTy->getElementType())) + .get(); + break; } else if (resultType->isExtVectorType()) { if (Context.getLangOpts().OpenCL && Context.getLangOpts().getOpenCLCompatibleVersion() < 120) { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f347066..5b3e89f 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3006,6 +3006,24 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { TheCall->setType(CounterHandleTy); break; } + case Builtin::BI__builtin_hlsl_resource_getdimensions_x: { + ASTContext &AST = SemaRef.getASTContext(); + if (SemaRef.checkArgCount(TheCall, 2) || + CheckResourceHandle(&SemaRef, TheCall, 0) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) || + CheckModifiableLValue(&SemaRef, TheCall, 1)) + return true; + break; + } + case Builtin::BI__builtin_hlsl_resource_getstride: { + ASTContext &AST = SemaRef.getASTContext(); + if (SemaRef.checkArgCount(TheCall, 2) || + CheckResourceHandle(&SemaRef, TheCall, 0) || + CheckArgTypeMatches(&SemaRef, TheCall->getArg(1), AST.UnsignedIntTy) || + CheckModifiableLValue(&SemaRef, TheCall, 1)) + return true; + break; + } case Builtin::BI__builtin_hlsl_and: case Builtin::BI__builtin_hlsl_or: { if (SemaRef.checkArgCount(TheCall, 2)) diff --git a/clang/lib/Sema/SemaRISCV.cpp b/clang/lib/Sema/SemaRISCV.cpp index 3ba93ff9..c5ef0d5 100644 --- a/clang/lib/Sema/SemaRISCV.cpp +++ b/clang/lib/Sema/SemaRISCV.cpp @@ -1464,7 +1464,8 @@ void SemaRISCV::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D, } else if (Info.ElementType->isBFloat16Type() && !FeatureMap.lookup("zvfbfmin") && - !FeatureMap.lookup("xandesvbfhcvt")) + !FeatureMap.lookup("xandesvbfhcvt") && + !FeatureMap.lookup("experimental-zvfbfa")) if (DeclareAndesVectorBuiltins) { Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfbfmin or xandesvbfhcvt"; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index bec2820..ca7e3b2 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -35,6 +35,7 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/ADT/SmallVectorExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/SaveAndRestore.h" @@ -4487,6 +4488,119 @@ ExprResult Sema::SubstConstraintExprWithoutSatisfaction( return Instantiator.TransformExpr(E); } +ExprResult Sema::SubstConceptTemplateArguments( + const ConceptSpecializationExpr *CSE, const Expr *ConstraintExpr, + const MultiLevelTemplateArgumentList &MLTAL) { + TemplateInstantiator Instantiator(*this, MLTAL, SourceLocation(), + DeclarationName()); + const ASTTemplateArgumentListInfo *ArgsAsWritten = + CSE->getTemplateArgsAsWritten(); + TemplateArgumentListInfo SubstArgs(ArgsAsWritten->getLAngleLoc(), + ArgsAsWritten->getRAngleLoc()); + + Sema::InstantiatingTemplate Inst( + *this, ArgsAsWritten->arguments().front().getSourceRange().getBegin(), + Sema::InstantiatingTemplate::ConstraintNormalization{}, + CSE->getNamedConcept(), + ArgsAsWritten->arguments().front().getSourceRange()); + + if (Inst.isInvalid()) + return ExprError(); + + if (Instantiator.TransformConceptTemplateArguments( + ArgsAsWritten->getTemplateArgs(), + ArgsAsWritten->getTemplateArgs() + + ArgsAsWritten->getNumTemplateArgs(), + SubstArgs)) + return true; + + llvm::SmallVector<TemplateArgument, 4> NewArgList = llvm::map_to_vector( + SubstArgs.arguments(), + [](const TemplateArgumentLoc &Loc) { return Loc.getArgument(); }); + + MultiLevelTemplateArgumentList MLTALForConstraint = + getTemplateInstantiationArgs( + CSE->getNamedConcept(), + CSE->getNamedConcept()->getLexicalDeclContext(), + /*Final=*/false, + /*Innermost=*/NewArgList, + /*RelativeToPrimary=*/true, + /*Pattern=*/nullptr, + /*ForConstraintInstantiation=*/true); + + // Rebuild a constraint, only substituting non-dependent concept names + // and nothing else. + // Given C<SomeType, SomeValue, SomeConceptName, SomeDependentConceptName>. + // only SomeConceptName is substituted, in the constraint expression of C. + struct ConstraintExprTransformer : TreeTransform<ConstraintExprTransformer> { + using Base = TreeTransform<ConstraintExprTransformer>; + MultiLevelTemplateArgumentList &MLTAL; + + ConstraintExprTransformer(Sema &SemaRef, + MultiLevelTemplateArgumentList &MLTAL) + : TreeTransform(SemaRef), MLTAL(MLTAL) {} + + ExprResult TransformExpr(Expr *E) { + if (!E) + return E; + switch (E->getStmtClass()) { + case Stmt::BinaryOperatorClass: + case Stmt::ConceptSpecializationExprClass: + case Stmt::ParenExprClass: + case Stmt::UnresolvedLookupExprClass: + return Base::TransformExpr(E); + default: + break; + } + return E; + } + + // Rebuild both branches of a conjunction / disjunction + // even if there is a substitution failure in one of + // the branch. + ExprResult TransformBinaryOperator(BinaryOperator *E) { + if (!(E->getOpcode() == BinaryOperatorKind::BO_LAnd || + E->getOpcode() == BinaryOperatorKind::BO_LOr)) + return E; + + ExprResult LHS = TransformExpr(E->getLHS()); + ExprResult RHS = TransformExpr(E->getRHS()); + + if (LHS.get() == E->getLHS() && RHS.get() == E->getRHS()) + return E; + + return BinaryOperator::Create(SemaRef.Context, LHS.get(), RHS.get(), + E->getOpcode(), SemaRef.Context.BoolTy, + VK_PRValue, OK_Ordinary, + E->getOperatorLoc(), FPOptionsOverride{}); + } + + bool TransformTemplateArgument(const TemplateArgumentLoc &Input, + TemplateArgumentLoc &Output, + bool Uneval = false) { + if (Input.getArgument().isConceptOrConceptTemplateParameter()) + return Base::TransformTemplateArgument(Input, Output, Uneval); + + Output = Input; + return false; + } + + ExprResult TransformUnresolvedLookupExpr(UnresolvedLookupExpr *E, + bool IsAddressOfOperand = false) { + if (E->isConceptReference()) { + ExprResult Res = SemaRef.SubstExpr(E, MLTAL); + return Res; + } + return E; + } + }; + + ConstraintExprTransformer Transformer(*this, MLTALForConstraint); + ExprResult Res = + Transformer.TransformExpr(const_cast<Expr *>(ConstraintExpr)); + return Res; +} + ExprResult Sema::SubstInitializer(Expr *Init, const MultiLevelTemplateArgumentList &TemplateArgs, bool CXXDirectInit) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 468bc1d..4863b45 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -707,6 +707,23 @@ static void instantiateDependentAMDGPUMaxNumWorkGroupsAttr( S.AMDGPU().addAMDGPUMaxNumWorkGroupsAttr(New, Attr, XExpr, YExpr, ZExpr); } +static void instantiateDependentCUDAClusterDimsAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const CUDAClusterDimsAttr &Attr, Decl *New) { + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + auto SubstElt = [&S, &TemplateArgs](Expr *E) { + return E ? S.SubstExpr(E, TemplateArgs).get() : nullptr; + }; + + Expr *XExpr = SubstElt(Attr.getX()); + Expr *YExpr = SubstElt(Attr.getY()); + Expr *ZExpr = SubstElt(Attr.getZ()); + + S.addClusterDimsAttr(New, Attr, XExpr, YExpr, ZExpr); +} + // This doesn't take any template parameters, but we have a custom action that // needs to happen when the kernel itself is instantiated. We need to run the // ItaniumMangler to mark the names required to name this kernel. @@ -765,10 +782,18 @@ static bool isRelevantAttr(Sema &S, const Decl *D, const Attr *A) { static void instantiateDependentHLSLParamModifierAttr( Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, - const HLSLParamModifierAttr *Attr, Decl *New) { - ParmVarDecl *P = cast<ParmVarDecl>(New); - P->addAttr(Attr->clone(S.getASTContext())); - P->setType(S.HLSL().getInoutParameterType(P->getType())); + const HLSLParamModifierAttr *Attr, const Decl *Old, Decl *New) { + ParmVarDecl *NewParm = cast<ParmVarDecl>(New); + NewParm->addAttr(Attr->clone(S.getASTContext())); + + const Type *OldParmTy = cast<ParmVarDecl>(Old)->getType().getTypePtr(); + if (OldParmTy->isDependentType() && Attr->isAnyOut()) + NewParm->setType(S.HLSL().getInoutParameterType(NewParm->getType())); + + assert( + (!Attr->isAnyOut() || (NewParm->getType().isRestrictQualified() && + NewParm->getType()->isReferenceType())) && + "out or inout parameter type must be a reference and restrict qualified"); } void Sema::InstantiateAttrsForDecl( @@ -921,9 +946,14 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, *this, TemplateArgs, *AMDGPUMaxNumWorkGroups, New); } + if (const auto *CUDAClusterDims = dyn_cast<CUDAClusterDimsAttr>(TmplAttr)) { + instantiateDependentCUDAClusterDimsAttr(*this, TemplateArgs, + *CUDAClusterDims, New); + } + if (const auto *ParamAttr = dyn_cast<HLSLParamModifierAttr>(TmplAttr)) { instantiateDependentHLSLParamModifierAttr(*this, TemplateArgs, ParamAttr, - New); + Tmpl, New); continue; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 638904d..7c1fb12 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2517,12 +2517,18 @@ QualType Sema::BuildMatrixType(QualType ElementTy, Expr *NumRows, Expr *NumCols, Diag(AttrLoc, diag::err_attribute_zero_size) << "matrix" << ColRange; return QualType(); } - if (!ConstantMatrixType::isDimensionValid(MatrixRows)) { + if (MatrixRows > Context.getLangOpts().MaxMatrixDimension && + MatrixColumns > Context.getLangOpts().MaxMatrixDimension) { + Diag(AttrLoc, diag::err_attribute_size_too_large) + << RowRange << ColRange << "matrix row and column"; + return QualType(); + } + if (MatrixRows > Context.getLangOpts().MaxMatrixDimension) { Diag(AttrLoc, diag::err_attribute_size_too_large) << RowRange << "matrix row"; return QualType(); } - if (!ConstantMatrixType::isDimensionValid(MatrixColumns)) { + if (MatrixColumns > Context.getLangOpts().MaxMatrixDimension) { Diag(AttrLoc, diag::err_attribute_size_too_large) << ColRange << "matrix column"; return QualType(); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 86896ab..29f0c30 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -694,6 +694,12 @@ public: TemplateArgumentListInfo &Outputs, bool Uneval = false); + template <typename InputIterator> + bool TransformConceptTemplateArguments(InputIterator First, + InputIterator Last, + TemplateArgumentListInfo &Outputs, + bool Uneval = false); + /// Checks if the argument pack from \p In will need to be expanded and does /// the necessary prework. /// Whether the expansion is needed is captured in Info.Expand. @@ -5192,6 +5198,49 @@ bool TreeTransform<Derived>::TransformTemplateArguments( return false; } +template <typename Derived> +template <typename InputIterator> +bool TreeTransform<Derived>::TransformConceptTemplateArguments( + InputIterator First, InputIterator Last, TemplateArgumentListInfo &Outputs, + bool Uneval) { + + // [C++26][temp.constr.normal] + // any non-dependent concept template argument + // is substituted into the constraint-expression of C. + auto isNonDependentConceptArgument = [](const TemplateArgument &Arg) { + return !Arg.isDependent() && Arg.isConceptOrConceptTemplateParameter(); + }; + + for (; First != Last; ++First) { + TemplateArgumentLoc Out; + TemplateArgumentLoc In = *First; + + if (In.getArgument().getKind() == TemplateArgument::Pack) { + typedef TemplateArgumentLocInventIterator<Derived, + TemplateArgument::pack_iterator> + PackLocIterator; + if (TransformConceptTemplateArguments( + PackLocIterator(*this, In.getArgument().pack_begin()), + PackLocIterator(*this, In.getArgument().pack_end()), Outputs, + Uneval)) + return true; + continue; + } + + if (!isNonDependentConceptArgument(In.getArgument())) { + Outputs.addArgument(In); + continue; + } + + if (getDerived().TransformTemplateArgument(In, Out, Uneval)) + return true; + + Outputs.addArgument(Out); + } + + return false; +} + // FIXME: Find ways to reduce code duplication for pack expansions. template <typename Derived> bool TreeTransform<Derived>::PreparePackForExpansion(TemplateArgumentLoc In, |