1*9a887f65SVitaly Buka //===--- VarBypassDetector.cpp - Bypass jumps detector ------------*- C++ -*-=//
264c80b4eSVitaly Buka //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
664c80b4eSVitaly Buka //
764c80b4eSVitaly Buka //===----------------------------------------------------------------------===//
864c80b4eSVitaly Buka 
964c80b4eSVitaly Buka #include "VarBypassDetector.h"
1064c80b4eSVitaly Buka 
1164c80b4eSVitaly Buka #include "clang/AST/Decl.h"
1264c80b4eSVitaly Buka #include "clang/AST/Expr.h"
1364c80b4eSVitaly Buka #include "clang/AST/Stmt.h"
1464c80b4eSVitaly Buka 
1564c80b4eSVitaly Buka using namespace clang;
1664c80b4eSVitaly Buka using namespace CodeGen;
1764c80b4eSVitaly Buka 
1864c80b4eSVitaly Buka /// Clear the object and pre-process for the given statement, usually function
1964c80b4eSVitaly Buka /// body statement.
Init(const Stmt * Body)2064c80b4eSVitaly Buka void VarBypassDetector::Init(const Stmt *Body) {
2164c80b4eSVitaly Buka   FromScopes.clear();
2264c80b4eSVitaly Buka   ToScopes.clear();
2364c80b4eSVitaly Buka   Bypasses.clear();
2464c80b4eSVitaly Buka   Scopes = {{~0U, nullptr}};
2564c80b4eSVitaly Buka   unsigned ParentScope = 0;
2664c80b4eSVitaly Buka   AlwaysBypassed = !BuildScopeInformation(Body, ParentScope);
2764c80b4eSVitaly Buka   if (!AlwaysBypassed)
2864c80b4eSVitaly Buka     Detect();
2964c80b4eSVitaly Buka }
3064c80b4eSVitaly Buka 
3164c80b4eSVitaly Buka /// Build scope information for a declaration that is part of a DeclStmt.
3264c80b4eSVitaly Buka /// Returns false if we failed to build scope information and can't tell for
3364c80b4eSVitaly Buka /// which vars are being bypassed.
BuildScopeInformation(const Decl * D,unsigned & ParentScope)3464c80b4eSVitaly Buka bool VarBypassDetector::BuildScopeInformation(const Decl *D,
3564c80b4eSVitaly Buka                                               unsigned &ParentScope) {
3664c80b4eSVitaly Buka   const VarDecl *VD = dyn_cast<VarDecl>(D);
3764c80b4eSVitaly Buka   if (VD && VD->hasLocalStorage()) {
3864c80b4eSVitaly Buka     Scopes.push_back({ParentScope, VD});
3964c80b4eSVitaly Buka     ParentScope = Scopes.size() - 1;
4064c80b4eSVitaly Buka   }
4164c80b4eSVitaly Buka 
4264c80b4eSVitaly Buka   if (const VarDecl *VD = dyn_cast<VarDecl>(D))
4364c80b4eSVitaly Buka     if (const Expr *Init = VD->getInit())
4464c80b4eSVitaly Buka       return BuildScopeInformation(Init, ParentScope);
4564c80b4eSVitaly Buka 
4664c80b4eSVitaly Buka   return true;
4764c80b4eSVitaly Buka }
4864c80b4eSVitaly Buka 
4964c80b4eSVitaly Buka /// Walk through the statements, adding any labels or gotos to
5064c80b4eSVitaly Buka /// LabelAndGotoScopes and recursively walking the AST as needed.
5164c80b4eSVitaly Buka /// Returns false if we failed to build scope information and can't tell for
5264c80b4eSVitaly Buka /// which vars are being bypassed.
BuildScopeInformation(const Stmt * S,unsigned & origParentScope)5364c80b4eSVitaly Buka bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
5464c80b4eSVitaly Buka                                               unsigned &origParentScope) {
5564c80b4eSVitaly Buka   // If this is a statement, rather than an expression, scopes within it don't
5664c80b4eSVitaly Buka   // propagate out into the enclosing scope. Otherwise we have to worry about
5764c80b4eSVitaly Buka   // block literals, which have the lifetime of their enclosing statement.
5864c80b4eSVitaly Buka   unsigned independentParentScope = origParentScope;
5964c80b4eSVitaly Buka   unsigned &ParentScope =
6064c80b4eSVitaly Buka       ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope
6164c80b4eSVitaly Buka                                            : independentParentScope);
6264c80b4eSVitaly Buka 
6364c80b4eSVitaly Buka   unsigned StmtsToSkip = 0u;
6464c80b4eSVitaly Buka 
6564c80b4eSVitaly Buka   switch (S->getStmtClass()) {
6664c80b4eSVitaly Buka   case Stmt::IndirectGotoStmtClass:
6764c80b4eSVitaly Buka     return false;
6864c80b4eSVitaly Buka 
6964c80b4eSVitaly Buka   case Stmt::SwitchStmtClass:
7064c80b4eSVitaly Buka     if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
7164c80b4eSVitaly Buka       if (!BuildScopeInformation(Init, ParentScope))
7264c80b4eSVitaly Buka         return false;
7364c80b4eSVitaly Buka       ++StmtsToSkip;
7464c80b4eSVitaly Buka     }
7564c80b4eSVitaly Buka     if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
7664c80b4eSVitaly Buka       if (!BuildScopeInformation(Var, ParentScope))
7764c80b4eSVitaly Buka         return false;
7864c80b4eSVitaly Buka       ++StmtsToSkip;
7964c80b4eSVitaly Buka     }
804dc0b1acSReid Kleckner     LLVM_FALLTHROUGH;
8164c80b4eSVitaly Buka 
8264c80b4eSVitaly Buka   case Stmt::GotoStmtClass:
8364c80b4eSVitaly Buka     FromScopes.push_back({S, ParentScope});
8464c80b4eSVitaly Buka     break;
8564c80b4eSVitaly Buka 
8664c80b4eSVitaly Buka   case Stmt::DeclStmtClass: {
8764c80b4eSVitaly Buka     const DeclStmt *DS = cast<DeclStmt>(S);
8864c80b4eSVitaly Buka     for (auto *I : DS->decls())
8964c80b4eSVitaly Buka       if (!BuildScopeInformation(I, origParentScope))
9064c80b4eSVitaly Buka         return false;
9164c80b4eSVitaly Buka     return true;
9264c80b4eSVitaly Buka   }
9364c80b4eSVitaly Buka 
9464c80b4eSVitaly Buka   case Stmt::CaseStmtClass:
9564c80b4eSVitaly Buka   case Stmt::DefaultStmtClass:
9664c80b4eSVitaly Buka   case Stmt::LabelStmtClass:
972a8c18d9SAlexander Kornienko     llvm_unreachable("the loop below handles labels and cases");
9864c80b4eSVitaly Buka     break;
9964c80b4eSVitaly Buka 
10064c80b4eSVitaly Buka   default:
10164c80b4eSVitaly Buka     break;
10264c80b4eSVitaly Buka   }
10364c80b4eSVitaly Buka 
10464c80b4eSVitaly Buka   for (const Stmt *SubStmt : S->children()) {
10564c80b4eSVitaly Buka     if (!SubStmt)
10664c80b4eSVitaly Buka       continue;
10764c80b4eSVitaly Buka     if (StmtsToSkip) {
10864c80b4eSVitaly Buka       --StmtsToSkip;
10964c80b4eSVitaly Buka       continue;
11064c80b4eSVitaly Buka     }
11164c80b4eSVitaly Buka 
11264c80b4eSVitaly Buka     // Cases, labels, and defaults aren't "scope parents".  It's also
11364c80b4eSVitaly Buka     // important to handle these iteratively instead of recursively in
11464c80b4eSVitaly Buka     // order to avoid blowing out the stack.
11564c80b4eSVitaly Buka     while (true) {
11664c80b4eSVitaly Buka       const Stmt *Next;
11764c80b4eSVitaly Buka       if (const SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))
11864c80b4eSVitaly Buka         Next = SC->getSubStmt();
11964c80b4eSVitaly Buka       else if (const LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
12064c80b4eSVitaly Buka         Next = LS->getSubStmt();
12164c80b4eSVitaly Buka       else
12264c80b4eSVitaly Buka         break;
12364c80b4eSVitaly Buka 
12464c80b4eSVitaly Buka       ToScopes[SubStmt] = ParentScope;
12564c80b4eSVitaly Buka       SubStmt = Next;
12664c80b4eSVitaly Buka     }
12764c80b4eSVitaly Buka 
12864c80b4eSVitaly Buka     // Recursively walk the AST.
12964c80b4eSVitaly Buka     if (!BuildScopeInformation(SubStmt, ParentScope))
13064c80b4eSVitaly Buka       return false;
13164c80b4eSVitaly Buka   }
13264c80b4eSVitaly Buka   return true;
13364c80b4eSVitaly Buka }
13464c80b4eSVitaly Buka 
13564c80b4eSVitaly Buka /// Checks each jump and stores each variable declaration they bypass.
Detect()13664c80b4eSVitaly Buka void VarBypassDetector::Detect() {
13764c80b4eSVitaly Buka   for (const auto &S : FromScopes) {
13864c80b4eSVitaly Buka     const Stmt *St = S.first;
13964c80b4eSVitaly Buka     unsigned from = S.second;
14064c80b4eSVitaly Buka     if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) {
14164c80b4eSVitaly Buka       if (const LabelStmt *LS = GS->getLabel()->getStmt())
14264c80b4eSVitaly Buka         Detect(from, ToScopes[LS]);
14364c80b4eSVitaly Buka     } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) {
14464c80b4eSVitaly Buka       for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
14564c80b4eSVitaly Buka            SC = SC->getNextSwitchCase()) {
14664c80b4eSVitaly Buka         Detect(from, ToScopes[SC]);
14764c80b4eSVitaly Buka       }
14864c80b4eSVitaly Buka     } else {
14964c80b4eSVitaly Buka       llvm_unreachable("goto or switch was expected");
15064c80b4eSVitaly Buka     }
15164c80b4eSVitaly Buka   }
15264c80b4eSVitaly Buka }
15364c80b4eSVitaly Buka 
15464c80b4eSVitaly Buka /// Checks the jump and stores each variable declaration it bypasses.
Detect(unsigned From,unsigned To)15564c80b4eSVitaly Buka void VarBypassDetector::Detect(unsigned From, unsigned To) {
15664c80b4eSVitaly Buka   while (From != To) {
15764c80b4eSVitaly Buka     if (From < To) {
15864c80b4eSVitaly Buka       assert(Scopes[To].first < To);
15964c80b4eSVitaly Buka       const auto &ScopeTo = Scopes[To];
16064c80b4eSVitaly Buka       To = ScopeTo.first;
16164c80b4eSVitaly Buka       Bypasses.insert(ScopeTo.second);
16264c80b4eSVitaly Buka     } else {
16364c80b4eSVitaly Buka       assert(Scopes[From].first < From);
16464c80b4eSVitaly Buka       From = Scopes[From].first;
16564c80b4eSVitaly Buka     }
16664c80b4eSVitaly Buka   }
16764c80b4eSVitaly Buka }
168