144290647SDimitry Andric //===--- VarBypassDetector.h - Bypass jumps detector --------------*- C++ -*-=//
244290647SDimitry Andric //
344290647SDimitry Andric //                     The LLVM Compiler Infrastructure
444290647SDimitry Andric //
544290647SDimitry Andric // This file is distributed under the University of Illinois Open Source
644290647SDimitry Andric // License. See LICENSE.TXT for details.
744290647SDimitry Andric //
844290647SDimitry Andric //===----------------------------------------------------------------------===//
944290647SDimitry Andric 
1044290647SDimitry Andric #include "VarBypassDetector.h"
1144290647SDimitry Andric 
1244290647SDimitry Andric #include "clang/AST/Decl.h"
1344290647SDimitry Andric #include "clang/AST/Expr.h"
1444290647SDimitry Andric #include "clang/AST/Stmt.h"
1544290647SDimitry Andric 
1644290647SDimitry Andric using namespace clang;
1744290647SDimitry Andric using namespace CodeGen;
1844290647SDimitry Andric 
1944290647SDimitry Andric /// Clear the object and pre-process for the given statement, usually function
2044290647SDimitry Andric /// body statement.
Init(const Stmt * Body)2144290647SDimitry Andric void VarBypassDetector::Init(const Stmt *Body) {
2244290647SDimitry Andric   FromScopes.clear();
2344290647SDimitry Andric   ToScopes.clear();
2444290647SDimitry Andric   Bypasses.clear();
2544290647SDimitry Andric   Scopes = {{~0U, nullptr}};
2644290647SDimitry Andric   unsigned ParentScope = 0;
2744290647SDimitry Andric   AlwaysBypassed = !BuildScopeInformation(Body, ParentScope);
2844290647SDimitry Andric   if (!AlwaysBypassed)
2944290647SDimitry Andric     Detect();
3044290647SDimitry Andric }
3144290647SDimitry Andric 
3244290647SDimitry Andric /// Build scope information for a declaration that is part of a DeclStmt.
3344290647SDimitry Andric /// Returns false if we failed to build scope information and can't tell for
3444290647SDimitry Andric /// which vars are being bypassed.
BuildScopeInformation(const Decl * D,unsigned & ParentScope)3544290647SDimitry Andric bool VarBypassDetector::BuildScopeInformation(const Decl *D,
3644290647SDimitry Andric                                               unsigned &ParentScope) {
3744290647SDimitry Andric   const VarDecl *VD = dyn_cast<VarDecl>(D);
3844290647SDimitry Andric   if (VD && VD->hasLocalStorage()) {
3944290647SDimitry Andric     Scopes.push_back({ParentScope, VD});
4044290647SDimitry Andric     ParentScope = Scopes.size() - 1;
4144290647SDimitry Andric   }
4244290647SDimitry Andric 
4344290647SDimitry Andric   if (const VarDecl *VD = dyn_cast<VarDecl>(D))
4444290647SDimitry Andric     if (const Expr *Init = VD->getInit())
4544290647SDimitry Andric       return BuildScopeInformation(Init, ParentScope);
4644290647SDimitry Andric 
4744290647SDimitry Andric   return true;
4844290647SDimitry Andric }
4944290647SDimitry Andric 
5044290647SDimitry Andric /// Walk through the statements, adding any labels or gotos to
5144290647SDimitry Andric /// LabelAndGotoScopes and recursively walking the AST as needed.
5244290647SDimitry Andric /// Returns false if we failed to build scope information and can't tell for
5344290647SDimitry Andric /// which vars are being bypassed.
BuildScopeInformation(const Stmt * S,unsigned & origParentScope)5444290647SDimitry Andric bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
5544290647SDimitry Andric                                               unsigned &origParentScope) {
5644290647SDimitry Andric   // If this is a statement, rather than an expression, scopes within it don't
5744290647SDimitry Andric   // propagate out into the enclosing scope. Otherwise we have to worry about
5844290647SDimitry Andric   // block literals, which have the lifetime of their enclosing statement.
5944290647SDimitry Andric   unsigned independentParentScope = origParentScope;
6044290647SDimitry Andric   unsigned &ParentScope =
6144290647SDimitry Andric       ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope
6244290647SDimitry Andric                                            : independentParentScope);
6344290647SDimitry Andric 
6444290647SDimitry Andric   unsigned StmtsToSkip = 0u;
6544290647SDimitry Andric 
6644290647SDimitry Andric   switch (S->getStmtClass()) {
6744290647SDimitry Andric   case Stmt::IndirectGotoStmtClass:
6844290647SDimitry Andric     return false;
6944290647SDimitry Andric 
7044290647SDimitry Andric   case Stmt::SwitchStmtClass:
7144290647SDimitry Andric     if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
7244290647SDimitry Andric       if (!BuildScopeInformation(Init, ParentScope))
7344290647SDimitry Andric         return false;
7444290647SDimitry Andric       ++StmtsToSkip;
7544290647SDimitry Andric     }
7644290647SDimitry Andric     if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
7744290647SDimitry Andric       if (!BuildScopeInformation(Var, ParentScope))
7844290647SDimitry Andric         return false;
7944290647SDimitry Andric       ++StmtsToSkip;
8044290647SDimitry Andric     }
81*b5893f02SDimitry Andric     LLVM_FALLTHROUGH;
8244290647SDimitry Andric 
8344290647SDimitry Andric   case Stmt::GotoStmtClass:
8444290647SDimitry Andric     FromScopes.push_back({S, ParentScope});
8544290647SDimitry Andric     break;
8644290647SDimitry Andric 
8744290647SDimitry Andric   case Stmt::DeclStmtClass: {
8844290647SDimitry Andric     const DeclStmt *DS = cast<DeclStmt>(S);
8944290647SDimitry Andric     for (auto *I : DS->decls())
9044290647SDimitry Andric       if (!BuildScopeInformation(I, origParentScope))
9144290647SDimitry Andric         return false;
9244290647SDimitry Andric     return true;
9344290647SDimitry Andric   }
9444290647SDimitry Andric 
9544290647SDimitry Andric   case Stmt::CaseStmtClass:
9644290647SDimitry Andric   case Stmt::DefaultStmtClass:
9744290647SDimitry Andric   case Stmt::LabelStmtClass:
984ba319b5SDimitry Andric     llvm_unreachable("the loop below handles labels and cases");
9944290647SDimitry Andric     break;
10044290647SDimitry Andric 
10144290647SDimitry Andric   default:
10244290647SDimitry Andric     break;
10344290647SDimitry Andric   }
10444290647SDimitry Andric 
10544290647SDimitry Andric   for (const Stmt *SubStmt : S->children()) {
10644290647SDimitry Andric     if (!SubStmt)
10744290647SDimitry Andric       continue;
10844290647SDimitry Andric     if (StmtsToSkip) {
10944290647SDimitry Andric       --StmtsToSkip;
11044290647SDimitry Andric       continue;
11144290647SDimitry Andric     }
11244290647SDimitry Andric 
11344290647SDimitry Andric     // Cases, labels, and defaults aren't "scope parents".  It's also
11444290647SDimitry Andric     // important to handle these iteratively instead of recursively in
11544290647SDimitry Andric     // order to avoid blowing out the stack.
11644290647SDimitry Andric     while (true) {
11744290647SDimitry Andric       const Stmt *Next;
11844290647SDimitry Andric       if (const SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))
11944290647SDimitry Andric         Next = SC->getSubStmt();
12044290647SDimitry Andric       else if (const LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
12144290647SDimitry Andric         Next = LS->getSubStmt();
12244290647SDimitry Andric       else
12344290647SDimitry Andric         break;
12444290647SDimitry Andric 
12544290647SDimitry Andric       ToScopes[SubStmt] = ParentScope;
12644290647SDimitry Andric       SubStmt = Next;
12744290647SDimitry Andric     }
12844290647SDimitry Andric 
12944290647SDimitry Andric     // Recursively walk the AST.
13044290647SDimitry Andric     if (!BuildScopeInformation(SubStmt, ParentScope))
13144290647SDimitry Andric       return false;
13244290647SDimitry Andric   }
13344290647SDimitry Andric   return true;
13444290647SDimitry Andric }
13544290647SDimitry Andric 
13644290647SDimitry Andric /// Checks each jump and stores each variable declaration they bypass.
Detect()13744290647SDimitry Andric void VarBypassDetector::Detect() {
13844290647SDimitry Andric   for (const auto &S : FromScopes) {
13944290647SDimitry Andric     const Stmt *St = S.first;
14044290647SDimitry Andric     unsigned from = S.second;
14144290647SDimitry Andric     if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) {
14244290647SDimitry Andric       if (const LabelStmt *LS = GS->getLabel()->getStmt())
14344290647SDimitry Andric         Detect(from, ToScopes[LS]);
14444290647SDimitry Andric     } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) {
14544290647SDimitry Andric       for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
14644290647SDimitry Andric            SC = SC->getNextSwitchCase()) {
14744290647SDimitry Andric         Detect(from, ToScopes[SC]);
14844290647SDimitry Andric       }
14944290647SDimitry Andric     } else {
15044290647SDimitry Andric       llvm_unreachable("goto or switch was expected");
15144290647SDimitry Andric     }
15244290647SDimitry Andric   }
15344290647SDimitry Andric }
15444290647SDimitry Andric 
15544290647SDimitry Andric /// Checks the jump and stores each variable declaration it bypasses.
Detect(unsigned From,unsigned To)15644290647SDimitry Andric void VarBypassDetector::Detect(unsigned From, unsigned To) {
15744290647SDimitry Andric   while (From != To) {
15844290647SDimitry Andric     if (From < To) {
15944290647SDimitry Andric       assert(Scopes[To].first < To);
16044290647SDimitry Andric       const auto &ScopeTo = Scopes[To];
16144290647SDimitry Andric       To = ScopeTo.first;
16244290647SDimitry Andric       Bypasses.insert(ScopeTo.second);
16344290647SDimitry Andric     } else {
16444290647SDimitry Andric       assert(Scopes[From].first < From);
16544290647SDimitry Andric       From = Scopes[From].first;
16644290647SDimitry Andric     }
16744290647SDimitry Andric   }
16844290647SDimitry Andric }
169