================ @@ -290,3 +294,295 @@ void SemaHLSL::DiagnoseAttrStageMismatch( << A << HLSLShaderAttr::ConvertShaderTypeToStr(Stage) << (AllowedStages.size() != 1) << join(StageStrings, ", "); } + +namespace { + +/// This class implements HLSL availability diagnostics for default +/// and relaxed mode +/// +/// The goal of this diagnostic is to emit an error or warning when an +/// unavailable API is found in a code that is reachable from the shader +/// entry function or from an exported function (when compiling shader +/// library). +/// +/// This is done by traversing the AST of all shader entry point functions +/// and of all exported functions, and any functions that are refrenced +/// from this AST. In other words, any function that are reachable from +/// the entry points. +class DiagnoseHLSLAvailability + : public RecursiveASTVisitor<DiagnoseHLSLAvailability> { + // HEKOTAS this is probably not needed + // typedef RecursiveASTVisitor<DiagnoseHLSLAvailability> Base; + + Sema &SemaRef; + + // Stack of functions to be scaned + llvm::SmallVector<const FunctionDecl *, 8> DeclsToScan; + + // List of functions that were already scanned and in which environment. + // + // Maps FunctionDecl to a unsigned number that represents a set of shader + // environments the function has been scanned for. + // Since HLSLShaderAttr::ShaderType enum is generated from Attr.td and is + // defined without any assigned values, it is guaranteed to be numbered + // sequentially from 0 up and we can use it to 'index' individual bits + // in the set. + // The N'th bit in the set will be set if the function has been scanned + // in shader environment whose ShaderType integer value equals N. + // For example, if a function has been scanned in compute and pixel stage + // environment, the value will be 0x21 (100001 binary) because + // (int)HLSLShaderAttr::ShaderType::Pixel == 1 and + // (int)HLSLShaderAttr::ShaderType::Compute == 5. + llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls; + + // Do not access these directly, use the get/set methods below to make + // sure the values are in sync + llvm::Triple::EnvironmentType CurrentShaderEnvironment; + unsigned CurrentShaderStageBit; + + // True if scanning a function that was already scanned in a different + // shader stage context, and therefore we should not report issues that + // depend only on shader model version because they would be duplicate. + bool ReportOnlyShaderStageIssues; + + void SetShaderStageContext(HLSLShaderAttr::ShaderType ShaderType) { + assert((((unsigned)1) << (unsigned)ShaderType) != 0 && + "ShaderType is too big for this bitmap"); + CurrentShaderEnvironment = HLSLShaderAttr::getTypeAsEnvironment(ShaderType); + CurrentShaderStageBit = (1 << ShaderType); + } + void SetUnknownShaderStageContext() { + CurrentShaderEnvironment = + llvm::Triple::EnvironmentType::UnknownEnvironment; + CurrentShaderStageBit = (1 << 31); + } + llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() { + return CurrentShaderEnvironment; + } + bool InUnknownShaderStageContext() { + return CurrentShaderEnvironment == + llvm::Triple::EnvironmentType::UnknownEnvironment; + } + + // Scanning methods + void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr); + void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA, + SourceRange Range); + const AvailabilityAttr *FindAvailabilityAttr(const Decl *D); + bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA); + bool WasAlreadyScannedInCurrentShaderStage(const FunctionDecl *FD, + bool *WasNeverScanned = nullptr); + void AddToScannedFunctions(const FunctionDecl *FD); + +public: + DiagnoseHLSLAvailability(Sema &SemaRef) : SemaRef(SemaRef) {} + + // AST traversal methods + void RunOnTranslationUnit(const TranslationUnitDecl *TU); + void RunOnFunction(const FunctionDecl *FD); + + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl()); + if (FD) + HandleFunctionOrMethodRef(FD, DRE); + return true; + } + + bool VisitMemberExpr(MemberExpr *ME) { + FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl()); + if (FD) + HandleFunctionOrMethodRef(FD, ME); + return true; + } +}; + +// Returns true if the function has already been scanned in the current +// shader environment. WasNeverScanned will be set to true if the function +// has never been scanned before for any shader environment. +bool DiagnoseHLSLAvailability::WasAlreadyScannedInCurrentShaderStage( + const FunctionDecl *FD, bool *WasNeverScanned) { ---------------- hekota wrote:
Got it. I was trying to avoid double lookup in the hash table while keeping the bitmap operations just in the helper methods. https://github.com/llvm/llvm-project/pull/92704 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits