| //===--- VarBypassDetector.h - Bypass jumps detector --------------*- C++ -*-=// | 
 | // | 
 | // 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 | 
 | // | 
 | //===----------------------------------------------------------------------===// | 
 |  | 
 | #include "VarBypassDetector.h" | 
 |  | 
 | #include "clang/AST/Decl.h" | 
 | #include "clang/AST/Expr.h" | 
 | #include "clang/AST/Stmt.h" | 
 |  | 
 | using namespace clang; | 
 | using namespace CodeGen; | 
 |  | 
 | /// Clear the object and pre-process for the given statement, usually function | 
 | /// body statement. | 
 | void VarBypassDetector::Init(const Stmt *Body) { | 
 |   FromScopes.clear(); | 
 |   ToScopes.clear(); | 
 |   Bypasses.clear(); | 
 |   Scopes = {{~0U, nullptr}}; | 
 |   unsigned ParentScope = 0; | 
 |   AlwaysBypassed = !BuildScopeInformation(Body, ParentScope); | 
 |   if (!AlwaysBypassed) | 
 |     Detect(); | 
 | } | 
 |  | 
 | /// Build scope information for a declaration that is part of a DeclStmt. | 
 | /// Returns false if we failed to build scope information and can't tell for | 
 | /// which vars are being bypassed. | 
 | bool VarBypassDetector::BuildScopeInformation(const Decl *D, | 
 |                                               unsigned &ParentScope) { | 
 |   const VarDecl *VD = dyn_cast<VarDecl>(D); | 
 |   if (VD && VD->hasLocalStorage()) { | 
 |     Scopes.push_back({ParentScope, VD}); | 
 |     ParentScope = Scopes.size() - 1; | 
 |   } | 
 |  | 
 |   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) | 
 |     if (const Expr *Init = VD->getInit()) | 
 |       return BuildScopeInformation(Init, ParentScope); | 
 |  | 
 |   return true; | 
 | } | 
 |  | 
 | /// Walk through the statements, adding any labels or gotos to | 
 | /// LabelAndGotoScopes and recursively walking the AST as needed. | 
 | /// Returns false if we failed to build scope information and can't tell for | 
 | /// which vars are being bypassed. | 
 | bool VarBypassDetector::BuildScopeInformation(const Stmt *S, | 
 |                                               unsigned &origParentScope) { | 
 |   // If this is a statement, rather than an expression, scopes within it don't | 
 |   // propagate out into the enclosing scope. Otherwise we have to worry about | 
 |   // block literals, which have the lifetime of their enclosing statement. | 
 |   unsigned independentParentScope = origParentScope; | 
 |   unsigned &ParentScope = | 
 |       ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope | 
 |                                            : independentParentScope); | 
 |  | 
 |   unsigned StmtsToSkip = 0u; | 
 |  | 
 |   switch (S->getStmtClass()) { | 
 |   case Stmt::IndirectGotoStmtClass: | 
 |     return false; | 
 |  | 
 |   case Stmt::SwitchStmtClass: | 
 |     if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) { | 
 |       if (!BuildScopeInformation(Init, ParentScope)) | 
 |         return false; | 
 |       ++StmtsToSkip; | 
 |     } | 
 |     if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) { | 
 |       if (!BuildScopeInformation(Var, ParentScope)) | 
 |         return false; | 
 |       ++StmtsToSkip; | 
 |     } | 
 |     LLVM_FALLTHROUGH; | 
 |  | 
 |   case Stmt::GotoStmtClass: | 
 |     FromScopes.push_back({S, ParentScope}); | 
 |     break; | 
 |  | 
 |   case Stmt::DeclStmtClass: { | 
 |     const DeclStmt *DS = cast<DeclStmt>(S); | 
 |     for (auto *I : DS->decls()) | 
 |       if (!BuildScopeInformation(I, origParentScope)) | 
 |         return false; | 
 |     return true; | 
 |   } | 
 |  | 
 |   case Stmt::CaseStmtClass: | 
 |   case Stmt::DefaultStmtClass: | 
 |   case Stmt::LabelStmtClass: | 
 |     llvm_unreachable("the loop below handles labels and cases"); | 
 |     break; | 
 |  | 
 |   default: | 
 |     break; | 
 |   } | 
 |  | 
 |   for (const Stmt *SubStmt : S->children()) { | 
 |     if (!SubStmt) | 
 |       continue; | 
 |     if (StmtsToSkip) { | 
 |       --StmtsToSkip; | 
 |       continue; | 
 |     } | 
 |  | 
 |     // Cases, labels, and defaults aren't "scope parents".  It's also | 
 |     // important to handle these iteratively instead of recursively in | 
 |     // order to avoid blowing out the stack. | 
 |     while (true) { | 
 |       const Stmt *Next; | 
 |       if (const SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt)) | 
 |         Next = SC->getSubStmt(); | 
 |       else if (const LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt)) | 
 |         Next = LS->getSubStmt(); | 
 |       else | 
 |         break; | 
 |  | 
 |       ToScopes[SubStmt] = ParentScope; | 
 |       SubStmt = Next; | 
 |     } | 
 |  | 
 |     // Recursively walk the AST. | 
 |     if (!BuildScopeInformation(SubStmt, ParentScope)) | 
 |       return false; | 
 |   } | 
 |   return true; | 
 | } | 
 |  | 
 | /// Checks each jump and stores each variable declaration they bypass. | 
 | void VarBypassDetector::Detect() { | 
 |   for (const auto &S : FromScopes) { | 
 |     const Stmt *St = S.first; | 
 |     unsigned from = S.second; | 
 |     if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) { | 
 |       if (const LabelStmt *LS = GS->getLabel()->getStmt()) | 
 |         Detect(from, ToScopes[LS]); | 
 |     } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) { | 
 |       for (const SwitchCase *SC = SS->getSwitchCaseList(); SC; | 
 |            SC = SC->getNextSwitchCase()) { | 
 |         Detect(from, ToScopes[SC]); | 
 |       } | 
 |     } else { | 
 |       llvm_unreachable("goto or switch was expected"); | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | /// Checks the jump and stores each variable declaration it bypasses. | 
 | void VarBypassDetector::Detect(unsigned From, unsigned To) { | 
 |   while (From != To) { | 
 |     if (From < To) { | 
 |       assert(Scopes[To].first < To); | 
 |       const auto &ScopeTo = Scopes[To]; | 
 |       To = ScopeTo.first; | 
 |       Bypasses.insert(ScopeTo.second); | 
 |     } else { | 
 |       assert(Scopes[From].first < From); | 
 |       From = Scopes[From].first; | 
 |     } | 
 |   } | 
 | } |