From 99ae07a3b5ad0bd6f55d991fc634237594fd674d Mon Sep 17 00:00:00 2001 From: EdwardWang Date: Wed, 13 Nov 2024 20:49:18 +0800 Subject: [PATCH] [refactor]: speed up compile time by reducing borrow cheking This patch reduces compile time by 10x at least for compiling TCC compiler. 1. In the previous, borrow checking happens for every FuncDecl, even the ones that do not use any memory safety features(owned, borrow). Because borrow checking is slow right now, we dont want to borrow check irrelevat code. 2. In this patch I add a precondition for borrow checking on a FuncDecl, which is: The FuncDecl must use bishengc language features. In that sense, a normal C func will never do borrow checking. 3. Reuse the utility of BSCFeatureFinder walker from Rewrite module, which I believe belongs to a much common module "AST", so I move it to AST module. And then Sema can use this class to tell whether a FuncDecl has used bsc features or not. TODO: improve the precondition, to make it more precise that borrow checking only happens when FD uses owned or borrow feature. I think that requires a new walker to collect info. --- clang/include/clang/AST/BSC/WalkerBSC.h | 355 ++++++++++++++++++++++ clang/include/clang/Sema/Sema.h | 2 + clang/lib/Frontend/Rewrite/RewriteBSC.cpp | 326 +------------------- clang/lib/Sema/BSC/SemaDeclBSC.cpp | 11 + clang/lib/Sema/Sema.cpp | 7 +- 5 files changed, 375 insertions(+), 326 deletions(-) create mode 100644 clang/include/clang/AST/BSC/WalkerBSC.h diff --git a/clang/include/clang/AST/BSC/WalkerBSC.h b/clang/include/clang/AST/BSC/WalkerBSC.h new file mode 100644 index 000000000000..5f8435f9c8d0 --- /dev/null +++ b/clang/include/clang/AST/BSC/WalkerBSC.h @@ -0,0 +1,355 @@ +//===- WalkerBSC.h - Classes for traversing BSC ASTs --*- BSC -*-=====// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +/// \file +/// Defines the BSC Walker utilities. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_AST_WALKERBSC_H +#define LLVM_CLANG_AST_WALKERBSC_H + +#if ENABLE_BSC + +#include "clang/AST/Decl.h" +#include "clang/AST/DeclBase.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/DeclarationName.h" +#include "clang/AST/Stmt.h" +#include "clang/AST/Type.h" +#include "clang/AST/TypeOrdering.h" +#include "clang/AST/DeclVisitor.h" +#include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeVisitor.h" + +namespace clang { +class ASTContext; + +static bool IsBSCDesugared(Decl *D, ASTContext *Context) { + for (auto DD : Context->BSCDesugaredMap) { + for (auto &DesugaredDecl : DD.second) { + if (isa(D)) { + NamedDecl *ND = cast(D); + if (ND == DesugaredDecl) { + return true; + } + } + } + } + return false; +} + +class BSCFeatureFinder : public StmtVisitor, + public DeclVisitor, + public TypeVisitor { +public: + using TypeVisitor::Visit; + using DeclVisitor::Visit; + using StmtVisitor::Visit; + + BSCFeatureFinder(ASTContext &Context) : Context(Context) {} + + /*--------------Types--------------*/ + + bool VisitType(const Type *T) { + if (isa(T)) { + if (VisitQualType(cast(T)->getPointeeType())) { + return true; + } + } + + if (isa(T)) { + if (VisitQualType(cast(T)->getInnerType())) { + return true; + } + } + + if (const FunctionProtoType *FPT = dyn_cast(T)) { + if (VisitQualType(FPT->getReturnType())) { + return true; + } + for (auto &P : FPT->getParamTypes()) { + if (VisitQualType(P)) { + return true; + } + } + } + + if (T->isTraitType() || T->isTraitPointerType() || T->hasTraitType()) { + return true; + } + return false; + } + + bool VisitQualType(QualType QT) { + if (QT.isOwnedQualified() || QT.isBorrowQualified() || + QT->hasBorrowFields() || QT->hasOwnedFields()) { + return true; + } + if (IsDesugaredFromTraitType(QT)) { + return true; + } + if (QT->getAs()) { + return true; + } + if (auto *TT = QT->getAs()) { + if (auto *TD = TT->getDecl()) + if (isa(TD) || isa(TD)) + return true; + } + if (VisitType(QT.getTypePtr())) { + return true; + } + return false; + } + + /*--------------Decls--------------*/ + bool VisitBSCMethodDecl(BSCMethodDecl *MD) { return true; } + + bool VisitFunctionDecl(FunctionDecl *FD) { + if (VisitQualType(FD->getType())) { + return true; + } + + // async related funcs + if (IsBSCDesugared(FD, &Context) || FD->isAsyncSpecified()) { + return true; + } + // safe / unsafe func + if (FD->getSafeZoneSpecifier() != SZ_None) { + return true; + } + // generic function + if (FD->getParent() && isa(FD->getParent()) && + cast(FD->getParent())->getDescribedClassTemplate()) { + return true; + } + if (FD->isTemplateInstantiation()) { + return true; + } + + if (FD->isConstexpr()) { + return true; + } + + for (auto *Parameter : FD->parameters()) { + if (Visit(Parameter)) { + return true; + } + if (VisitQualType(Parameter->getType())) { + return true; + } + } + + if (FD->doesThisDeclarationHaveABody()) { + if (Visit(FD->getBody())) { + return true; + } + } + return false; + } + bool VisitVarDecl(VarDecl *D) { + if (VisitQualType(D->getType())) { + return true; + } + if (D->isConstexpr()) { + return true; + } + + if (D->hasInit()) { + if (Visit((D->getInit()))) { + return true; + } + if (VisitQualType(D->getInit()->getType())) { + return true; + } + } + return false; + } + + bool VisitRecordDecl(RecordDecl *RD) { + if (IsBSCDesugared(RD, &Context)) { + return true; + } + + if (RD->isTrait() || RD->getDesugaredTraitDecl()) { + return true; + } + if (RD->isOwnedDecl()) { + return true; + } + for (auto Member : RD->fields()) { + if (Visit(Member)) { + return true; + } + if (VisitQualType(Member->getType())) { + return true; + } + } + return false; + } + + bool VisitStaticAssertDecl(StaticAssertDecl *D) { + return Visit(D->getAssertExpr()); + } + + bool VisitTypeAliasDecl(TypeAliasDecl *D) { + return true; + } + + bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + return true; + } + + bool VisitStmt(Stmt *S) { + for (auto *C : S->children()) { + if (C) { + if (Visit(C)) { + return true; + } + } + } + return false; + } + + /*--------------Stmts--------------*/ + bool VisitDeclStmt(DeclStmt *DS) { + for (auto *D : DS->decls()) { + if (Visit(D)) { + return true; + } + } + return false; + } + + bool VisitCompoundStmt(CompoundStmt *CS) { + if (CS->getCompSafeZoneSpecifier() != SZ_None) { + return true; + } + for (auto *S : CS->body()) { + if (Visit(S)) { + return true; + } + } + return false; + } + + bool VisitIfStmt(IfStmt *IS) { + if (IS->isConstexpr()) { + return true; + } + Visit(IS->getCond()); + if (IS->getConditionVariable()) { + if (Visit(IS->getConditionVariable())) { + return true; + } + } + if (IS->getThen()) { + if (Visit(IS->getThen())) { + return true; + } + } + if (IS->getElse()) { + if (Visit(IS->getElse())) { + return true; + } + } + return false; + } + + bool VisitInitListExpr(InitListExpr *ILE) { + if (VisitQualType(ILE->getType())) { + return true; + } + for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) { + if (ILE->getInit(i)) { + if (Visit(ILE->getInit(i))) { + return true; + } + } + } + return false; + } + + bool VisitCStyleCastExpr(CStyleCastExpr *E) { + if (VisitQualType(E->getType())) { + return true; + } + if (VisitExplicitCastExpr(E)) { + return true; + } + return false; + } + + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + if (VisitQualType(DRE->getType())) { + return true; + } + if (IsBSCDesugared(DRE->getDecl(), &Context)) { + return true; + } + + if (DRE->getDecl()->getKind() == Decl::BSCMethod) { + return true; + } + + if (DRE->getDecl()->getKind() == Decl::Function) { + FunctionDecl *FD = cast(DRE->getDecl()); + if (FD->isTemplateInstantiation() || FD->isConstexpr()) { + return true; + } + } + return false; + } + + bool VisitMemberExpr(MemberExpr *ME) { + if (VisitQualType(ME->getType())) { + return true; + } + if (Visit(ME->getBase())) { + return true; + } + if (IsBSCDesugared(ME->getMemberDecl(), &Context)) { + return true; + } + if (ME->getMemberDecl()->getKind() == Decl::BSCMethod) { + return true; + } + if (ME->getMemberDecl()->getKind() == Decl::Function) { + FunctionDecl *FD = cast(ME->getMemberDecl()); + if (FD->isTemplateInstantiation() || FD->isConstexpr()) { + return true; + } + } + return false; + } + +protected: + ASTContext &Context; + +private: + bool IsDesugaredFromTraitType(QualType T) { + while (T->isPointerType()) + T = T->getPointeeType(); + if (RecordDecl *RD = T->getAsRecordDecl()) { + if (auto *TST = dyn_cast_or_null(T)) { + TemplateDecl *TempT = TST->getTemplateName().getAsTemplateDecl(); + RD = dyn_cast_or_null(TempT->getTemplatedDecl()); + } + if (RD && RD->getDesugaredTraitDecl()) + return true; + } + return false; + } +}; + +} // namespace clang + +#endif // ENABLE_BSC + +#endif // LLVM_CLANG_AST_WALKERBSC_H \ No newline at end of file diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 432f48e52e2a..f1ce081b980c 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -12375,6 +12375,7 @@ public: AssignConvertType CheckTransparentUnionArgumentConstraints(QualType ArgType, ExprResult &RHS); + // BiShengC safety feature related APIs #if ENABLE_BSC bool CheckOwnedQualTypeCStyleCast(QualType LHSType, QualType RHSType); bool CheckOwnedQualTypeCStyleCast(QualType LHSType, QualType RHSType, SourceLocation RLoc); @@ -12425,6 +12426,7 @@ public: SourceLocation OpLoc); bool CheckOperatorDeclNeedAddToContext(Declarator &D); bool CheckOperatorFunReturnTypeIsLegal(FunctionDecl *FnDecl); + bool FindSafeFeatures(const FunctionDecl* FnDecl); #endif bool IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType); diff --git a/clang/lib/Frontend/Rewrite/RewriteBSC.cpp b/clang/lib/Frontend/Rewrite/RewriteBSC.cpp index 6f197d96f53f..5397f13ed0de 100644 --- a/clang/lib/Frontend/Rewrite/RewriteBSC.cpp +++ b/clang/lib/Frontend/Rewrite/RewriteBSC.cpp @@ -14,9 +14,7 @@ #include "clang/AST/AST.h" #include "clang/AST/ASTConsumer.h" -#include "clang/AST/DeclVisitor.h" -#include "clang/AST/StmtVisitor.h" -#include "clang/AST/TypeVisitor.h" +#include "clang/AST/BSC/WalkerBSC.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Rewrite/Core/Rewriter.h" @@ -221,25 +219,11 @@ void RewriteBSC::RewriteDecls(DeclContext *DC) { ReplaceText(BeginLocOfFirstDecl, endBuf - startBuf + 1, Str); } -static bool IsDesugared(Decl *D, ASTContext *Context) { - for (auto DD : Context->BSCDesugaredMap) { - for (auto &DesugaredDecl : DD.second) { - if (isa(D)) { - NamedDecl *ND = cast(D); - if (ND == DesugaredDecl) { - return true; - } - } - } - } - return false; -} - void RewriteBSC::GetSourceLocationsOfFirstDeclAndLastDecl() { for (DeclContext::decl_iterator D = TUDecl->decls_begin(), DEnd = TUDecl->decls_end(); D != DEnd; ++D) { - if (IsDesugared(*D, Context)) { + if (IsBSCDesugared(*D, Context)) { continue; } @@ -294,312 +278,6 @@ static bool HasTemplateSpecType(QualType QT, return false; } -namespace { -class BSCFeatureFinder : public StmtVisitor, - public DeclVisitor, - public TypeVisitor { -public: - using TypeVisitor::Visit; - using DeclVisitor::Visit; - using StmtVisitor::Visit; - - BSCFeatureFinder(ASTContext &Context) : Context(Context) {} - - /*--------------Types--------------*/ - - bool VisitType(const Type *T) { - if (isa(T)) { - if (VisitQualType(cast(T)->getPointeeType())) { - return true; - } - } - - if (isa(T)) { - if (VisitQualType(cast(T)->getInnerType())) { - return true; - } - } - - if (const FunctionProtoType *FPT = dyn_cast(T)) { - if (VisitQualType(FPT->getReturnType())) { - return true; - } - for (auto &P : FPT->getParamTypes()) { - if (VisitQualType(P)) { - return true; - } - } - } - - if (T->isTraitType() || T->isTraitPointerType() || T->hasTraitType()) { - return true; - } - return false; - } - - bool VisitQualType(QualType QT) { - if (QT.isOwnedQualified() || QT.isBorrowQualified() || - QT->hasBorrowFields() || QT->hasOwnedFields()) { - return true; - } - if (IsDesugaredFromTraitType(QT)) { - return true; - } - if (QT->getAs()) { - return true; - } - if (auto *TT = QT->getAs()) { - if (auto *TD = TT->getDecl()) - if (isa(TD) || isa(TD)) - return true; - } - if (VisitType(QT.getTypePtr())) { - return true; - } - return false; - } - - /*--------------Decls--------------*/ - bool VisitBSCMethodDecl(BSCMethodDecl *MD) { return true; } - - bool VisitFunctionDecl(FunctionDecl *FD) { - if (VisitQualType(FD->getType())) { - return true; - } - - // async related funcs - if (IsDesugared(FD, &Context) || FD->isAsyncSpecified()) { - return true; - } - // safe / unsafe func - if (FD->getSafeZoneSpecifier() != SZ_None) { - return true; - } - // generic function - if (FD->getParent() && isa(FD->getParent()) && - cast(FD->getParent())->getDescribedClassTemplate()) { - return true; - } - if (FD->isTemplateInstantiation()) { - return true; - } - - if (FD->isConstexpr()) { - return true; - } - - for (auto *Parameter : FD->parameters()) { - if (Visit(Parameter)) { - return true; - } - if (VisitQualType(Parameter->getType())) { - return true; - } - } - - if (FD->doesThisDeclarationHaveABody()) { - if (Visit(FD->getBody())) { - return true; - } - } - return false; - } - bool VisitVarDecl(VarDecl *D) { - if (VisitQualType(D->getType())) { - return true; - } - if (D->isConstexpr()) { - return true; - } - - if (D->hasInit()) { - if (Visit((D->getInit()))) { - return true; - } - if (VisitQualType(D->getInit()->getType())) { - return true; - } - } - return false; - } - - bool VisitRecordDecl(RecordDecl *RD) { - if (IsDesugared(RD, &Context)) { - return true; - } - - if (RD->isTrait() || RD->getDesugaredTraitDecl()) { - return true; - } - if (RD->isOwnedDecl()) { - return true; - } - for (auto Member : RD->fields()) { - if (Visit(Member)) { - return true; - } - if (VisitQualType(Member->getType())) { - return true; - } - } - return false; - } - - bool VisitStaticAssertDecl(StaticAssertDecl *D) { - return Visit(D->getAssertExpr()); - } - - bool VisitTypeAliasDecl(TypeAliasDecl *D) { - return true; - } - - bool VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { - return true; - } - - bool VisitStmt(Stmt *S) { - for (auto *C : S->children()) { - if (C) { - if (Visit(C)) { - return true; - } - } - } - return false; - } - - /*--------------Stmts--------------*/ - bool VisitDeclStmt(DeclStmt *DS) { - for (auto *D : DS->decls()) { - if (Visit(D)) { - return true; - } - } - return false; - } - - bool VisitCompoundStmt(CompoundStmt *CS) { - if (CS->getCompSafeZoneSpecifier() != SZ_None) { - return true; - } - for (auto *S : CS->body()) { - if (Visit(S)) { - return true; - } - } - return false; - } - - bool VisitIfStmt(IfStmt *IS) { - if (IS->isConstexpr()) { - return true; - } - Visit(IS->getCond()); - if (IS->getConditionVariable()) { - if (Visit(IS->getConditionVariable())) { - return true; - } - } - if (IS->getThen()) { - if (Visit(IS->getThen())) { - return true; - } - } - if (IS->getElse()) { - if (Visit(IS->getElse())) { - return true; - } - } - return false; - } - - bool VisitInitListExpr(InitListExpr *ILE) { - if (VisitQualType(ILE->getType())) { - return true; - } - for (unsigned i = 0, e = ILE->getNumInits(); i != e; ++i) { - if (ILE->getInit(i)) { - if (Visit(ILE->getInit(i))) { - return true; - } - } - } - return false; - } - - bool VisitCStyleCastExpr(CStyleCastExpr *E) { - if (VisitQualType(E->getType())) { - return true; - } - if (VisitExplicitCastExpr(E)) { - return true; - } - return false; - } - - bool VisitDeclRefExpr(DeclRefExpr *DRE) { - if (VisitQualType(DRE->getType())) { - return true; - } - if (IsDesugared(DRE->getDecl(), &Context)) { - return true; - } - - if (DRE->getDecl()->getKind() == Decl::BSCMethod) { - return true; - } - - if (DRE->getDecl()->getKind() == Decl::Function) { - FunctionDecl *FD = cast(DRE->getDecl()); - if (FD->isTemplateInstantiation() || FD->isConstexpr()) { - return true; - } - } - return false; - } - - bool VisitMemberExpr(MemberExpr *ME) { - if (VisitQualType(ME->getType())) { - return true; - } - if (Visit(ME->getBase())) { - return true; - } - if (IsDesugared(ME->getMemberDecl(), &Context)) { - return true; - } - if (ME->getMemberDecl()->getKind() == Decl::BSCMethod) { - return true; - } - if (ME->getMemberDecl()->getKind() == Decl::Function) { - FunctionDecl *FD = cast(ME->getMemberDecl()); - if (FD->isTemplateInstantiation() || FD->isConstexpr()) { - return true; - } - } - return false; - } - -protected: - ASTContext &Context; - -private: - bool IsDesugaredFromTraitType(QualType T) { - while (T->isPointerType()) - T = T->getPointeeType(); - if (RecordDecl *RD = T->getAsRecordDecl()) { - if (auto *TST = dyn_cast_or_null(T)) { - TemplateDecl *TempT = TST->getTemplateName().getAsTemplateDecl(); - RD = dyn_cast_or_null(TempT->getTemplatedDecl()); - } - if (RD && RD->getDesugaredTraitDecl()) - return true; - } - return false; - } -}; -} // namespace - void RewriteBSC::FindDeclsWithoutBSCFeature() { BSCFeatureFinder finder = BSCFeatureFinder(*Context); for (DeclContext::decl_iterator D = TUDecl->decls_begin(), diff --git a/clang/lib/Sema/BSC/SemaDeclBSC.cpp b/clang/lib/Sema/BSC/SemaDeclBSC.cpp index 35507066b744..184730d2bd6a 100644 --- a/clang/lib/Sema/BSC/SemaDeclBSC.cpp +++ b/clang/lib/Sema/BSC/SemaDeclBSC.cpp @@ -15,6 +15,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" +#include "clang/AST/BSC/WalkerBSC.h" using namespace clang; using namespace sema; @@ -144,4 +145,14 @@ bool Sema::CheckOperatorFunReturnTypeIsLegal(FunctionDecl *FnDecl) { } return true; } + +// Return true if any memory safe features are found in a FunctionDecl. +bool Sema::FindSafeFeatures(const FunctionDecl* FnDecl) { + if (!FnDecl) return false; + BSCFeatureFinder finder = BSCFeatureFinder(Context); + if (finder.Visit(const_cast(FnDecl))) { + return true; + } + return false; +} #endif \ No newline at end of file diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 6bd0b666c41f..148d167e209c 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2213,8 +2213,11 @@ Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, #if ENABLE_BSC bool DisableOwnershipCheck = getLangOpts().DisableOwnershipCheck; - if (!DisableOwnershipCheck) { - if (LangOpts.BSC && !isBSCCoroutine && + // If D does not use memory safety features like "owned, borrow, &mut, &const", + // we do not do borrow checking. + bool useSafeFeature = LangOpts.BSC ? FindSafeFeatures(dyn_cast_or_null(D)) : false; + if (!DisableOwnershipCheck && useSafeFeature) { + if (!isBSCCoroutine && (getDiagnostics().getNumErrors() == getDiagnostics().getNumOwnershipErrors() + getDiagnostics().getNumBorrowCheckErrors()) && D) -- Gitee