1 //===--- VarBypassDetector.h - Bypass jumps detector --------------*- C++ -*-=//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "VarBypassDetector.h"
12 #include "clang/AST/Decl.h"
13 #include "clang/AST/Expr.h"
14 #include "clang/AST/Stmt.h"
16 using namespace clang;
17 using namespace CodeGen;
19 /// Clear the object and pre-process for the given statement, usually function
21 void VarBypassDetector::Init(const Stmt *Body) {
25 Scopes = {{~0U, nullptr}};
26 unsigned ParentScope = 0;
27 AlwaysBypassed = !BuildScopeInformation(Body, ParentScope);
32 /// Build scope information for a declaration that is part of a DeclStmt.
33 /// Returns false if we failed to build scope information and can't tell for
34 /// which vars are being bypassed.
35 bool VarBypassDetector::BuildScopeInformation(const Decl *D,
36 unsigned &ParentScope) {
37 const VarDecl *VD = dyn_cast<VarDecl>(D);
38 if (VD && VD->hasLocalStorage()) {
39 Scopes.push_back({ParentScope, VD});
40 ParentScope = Scopes.size() - 1;
43 if (const VarDecl *VD = dyn_cast<VarDecl>(D))
44 if (const Expr *Init = VD->getInit())
45 return BuildScopeInformation(Init, ParentScope);
50 /// Walk through the statements, adding any labels or gotos to
51 /// LabelAndGotoScopes and recursively walking the AST as needed.
52 /// Returns false if we failed to build scope information and can't tell for
53 /// which vars are being bypassed.
54 bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
55 unsigned &origParentScope) {
56 // If this is a statement, rather than an expression, scopes within it don't
57 // propagate out into the enclosing scope. Otherwise we have to worry about
58 // block literals, which have the lifetime of their enclosing statement.
59 unsigned independentParentScope = origParentScope;
60 unsigned &ParentScope =
61 ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope
62 : independentParentScope);
64 unsigned StmtsToSkip = 0u;
66 switch (S->getStmtClass()) {
67 case Stmt::IndirectGotoStmtClass:
70 case Stmt::SwitchStmtClass:
71 if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
72 if (!BuildScopeInformation(Init, ParentScope))
76 if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
77 if (!BuildScopeInformation(Var, ParentScope))
83 case Stmt::GotoStmtClass:
84 FromScopes.push_back({S, ParentScope});
87 case Stmt::DeclStmtClass: {
88 const DeclStmt *DS = cast<DeclStmt>(S);
89 for (auto *I : DS->decls())
90 if (!BuildScopeInformation(I, origParentScope))
95 case Stmt::CaseStmtClass:
96 case Stmt::DefaultStmtClass:
97 case Stmt::LabelStmtClass:
98 llvm_unreachable("the loop below handles labels and cases");
105 for (const Stmt *SubStmt : S->children()) {
113 // Cases, labels, and defaults aren't "scope parents". It's also
114 // important to handle these iteratively instead of recursively in
115 // order to avoid blowing out the stack.
118 if (const SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))
119 Next = SC->getSubStmt();
120 else if (const LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
121 Next = LS->getSubStmt();
125 ToScopes[SubStmt] = ParentScope;
129 // Recursively walk the AST.
130 if (!BuildScopeInformation(SubStmt, ParentScope))
136 /// Checks each jump and stores each variable declaration they bypass.
137 void VarBypassDetector::Detect() {
138 for (const auto &S : FromScopes) {
139 const Stmt *St = S.first;
140 unsigned from = S.second;
141 if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) {
142 if (const LabelStmt *LS = GS->getLabel()->getStmt())
143 Detect(from, ToScopes[LS]);
144 } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) {
145 for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
146 SC = SC->getNextSwitchCase()) {
147 Detect(from, ToScopes[SC]);
150 llvm_unreachable("goto or switch was expected");
155 /// Checks the jump and stores each variable declaration it bypasses.
156 void VarBypassDetector::Detect(unsigned From, unsigned To) {
159 assert(Scopes[To].first < To);
160 const auto &ScopeTo = Scopes[To];
162 Bypasses.insert(ScopeTo.second);
164 assert(Scopes[From].first < From);
165 From = Scopes[From].first;