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