1*e038c9c4Sjoerg //===--- VarBypassDetector.cpp - Bypass jumps detector ------------*- C++ -*-=//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
97330f729Sjoerg #include "VarBypassDetector.h"
107330f729Sjoerg
117330f729Sjoerg #include "clang/AST/Decl.h"
127330f729Sjoerg #include "clang/AST/Expr.h"
137330f729Sjoerg #include "clang/AST/Stmt.h"
147330f729Sjoerg
157330f729Sjoerg using namespace clang;
167330f729Sjoerg using namespace CodeGen;
177330f729Sjoerg
187330f729Sjoerg /// Clear the object and pre-process for the given statement, usually function
197330f729Sjoerg /// body statement.
Init(const Stmt * Body)207330f729Sjoerg void VarBypassDetector::Init(const Stmt *Body) {
217330f729Sjoerg FromScopes.clear();
227330f729Sjoerg ToScopes.clear();
237330f729Sjoerg Bypasses.clear();
247330f729Sjoerg Scopes = {{~0U, nullptr}};
257330f729Sjoerg unsigned ParentScope = 0;
267330f729Sjoerg AlwaysBypassed = !BuildScopeInformation(Body, ParentScope);
277330f729Sjoerg if (!AlwaysBypassed)
287330f729Sjoerg Detect();
297330f729Sjoerg }
307330f729Sjoerg
317330f729Sjoerg /// Build scope information for a declaration that is part of a DeclStmt.
327330f729Sjoerg /// Returns false if we failed to build scope information and can't tell for
337330f729Sjoerg /// which vars are being bypassed.
BuildScopeInformation(const Decl * D,unsigned & ParentScope)347330f729Sjoerg bool VarBypassDetector::BuildScopeInformation(const Decl *D,
357330f729Sjoerg unsigned &ParentScope) {
367330f729Sjoerg const VarDecl *VD = dyn_cast<VarDecl>(D);
377330f729Sjoerg if (VD && VD->hasLocalStorage()) {
387330f729Sjoerg Scopes.push_back({ParentScope, VD});
397330f729Sjoerg ParentScope = Scopes.size() - 1;
407330f729Sjoerg }
417330f729Sjoerg
427330f729Sjoerg if (const VarDecl *VD = dyn_cast<VarDecl>(D))
437330f729Sjoerg if (const Expr *Init = VD->getInit())
447330f729Sjoerg return BuildScopeInformation(Init, ParentScope);
457330f729Sjoerg
467330f729Sjoerg return true;
477330f729Sjoerg }
487330f729Sjoerg
497330f729Sjoerg /// Walk through the statements, adding any labels or gotos to
507330f729Sjoerg /// LabelAndGotoScopes and recursively walking the AST as needed.
517330f729Sjoerg /// Returns false if we failed to build scope information and can't tell for
527330f729Sjoerg /// which vars are being bypassed.
BuildScopeInformation(const Stmt * S,unsigned & origParentScope)537330f729Sjoerg bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
547330f729Sjoerg unsigned &origParentScope) {
557330f729Sjoerg // If this is a statement, rather than an expression, scopes within it don't
567330f729Sjoerg // propagate out into the enclosing scope. Otherwise we have to worry about
577330f729Sjoerg // block literals, which have the lifetime of their enclosing statement.
587330f729Sjoerg unsigned independentParentScope = origParentScope;
597330f729Sjoerg unsigned &ParentScope =
607330f729Sjoerg ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope
617330f729Sjoerg : independentParentScope);
627330f729Sjoerg
637330f729Sjoerg unsigned StmtsToSkip = 0u;
647330f729Sjoerg
657330f729Sjoerg switch (S->getStmtClass()) {
667330f729Sjoerg case Stmt::IndirectGotoStmtClass:
677330f729Sjoerg return false;
687330f729Sjoerg
697330f729Sjoerg case Stmt::SwitchStmtClass:
707330f729Sjoerg if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
717330f729Sjoerg if (!BuildScopeInformation(Init, ParentScope))
727330f729Sjoerg return false;
737330f729Sjoerg ++StmtsToSkip;
747330f729Sjoerg }
757330f729Sjoerg if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
767330f729Sjoerg if (!BuildScopeInformation(Var, ParentScope))
777330f729Sjoerg return false;
787330f729Sjoerg ++StmtsToSkip;
797330f729Sjoerg }
807330f729Sjoerg LLVM_FALLTHROUGH;
817330f729Sjoerg
827330f729Sjoerg case Stmt::GotoStmtClass:
837330f729Sjoerg FromScopes.push_back({S, ParentScope});
847330f729Sjoerg break;
857330f729Sjoerg
867330f729Sjoerg case Stmt::DeclStmtClass: {
877330f729Sjoerg const DeclStmt *DS = cast<DeclStmt>(S);
887330f729Sjoerg for (auto *I : DS->decls())
897330f729Sjoerg if (!BuildScopeInformation(I, origParentScope))
907330f729Sjoerg return false;
917330f729Sjoerg return true;
927330f729Sjoerg }
937330f729Sjoerg
947330f729Sjoerg case Stmt::CaseStmtClass:
957330f729Sjoerg case Stmt::DefaultStmtClass:
967330f729Sjoerg case Stmt::LabelStmtClass:
977330f729Sjoerg llvm_unreachable("the loop below handles labels and cases");
987330f729Sjoerg break;
997330f729Sjoerg
1007330f729Sjoerg default:
1017330f729Sjoerg break;
1027330f729Sjoerg }
1037330f729Sjoerg
1047330f729Sjoerg for (const Stmt *SubStmt : S->children()) {
1057330f729Sjoerg if (!SubStmt)
1067330f729Sjoerg continue;
1077330f729Sjoerg if (StmtsToSkip) {
1087330f729Sjoerg --StmtsToSkip;
1097330f729Sjoerg continue;
1107330f729Sjoerg }
1117330f729Sjoerg
1127330f729Sjoerg // Cases, labels, and defaults aren't "scope parents". It's also
1137330f729Sjoerg // important to handle these iteratively instead of recursively in
1147330f729Sjoerg // order to avoid blowing out the stack.
1157330f729Sjoerg while (true) {
1167330f729Sjoerg const Stmt *Next;
1177330f729Sjoerg if (const SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))
1187330f729Sjoerg Next = SC->getSubStmt();
1197330f729Sjoerg else if (const LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
1207330f729Sjoerg Next = LS->getSubStmt();
1217330f729Sjoerg else
1227330f729Sjoerg break;
1237330f729Sjoerg
1247330f729Sjoerg ToScopes[SubStmt] = ParentScope;
1257330f729Sjoerg SubStmt = Next;
1267330f729Sjoerg }
1277330f729Sjoerg
1287330f729Sjoerg // Recursively walk the AST.
1297330f729Sjoerg if (!BuildScopeInformation(SubStmt, ParentScope))
1307330f729Sjoerg return false;
1317330f729Sjoerg }
1327330f729Sjoerg return true;
1337330f729Sjoerg }
1347330f729Sjoerg
1357330f729Sjoerg /// Checks each jump and stores each variable declaration they bypass.
Detect()1367330f729Sjoerg void VarBypassDetector::Detect() {
1377330f729Sjoerg for (const auto &S : FromScopes) {
1387330f729Sjoerg const Stmt *St = S.first;
1397330f729Sjoerg unsigned from = S.second;
1407330f729Sjoerg if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) {
1417330f729Sjoerg if (const LabelStmt *LS = GS->getLabel()->getStmt())
1427330f729Sjoerg Detect(from, ToScopes[LS]);
1437330f729Sjoerg } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) {
1447330f729Sjoerg for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
1457330f729Sjoerg SC = SC->getNextSwitchCase()) {
1467330f729Sjoerg Detect(from, ToScopes[SC]);
1477330f729Sjoerg }
1487330f729Sjoerg } else {
1497330f729Sjoerg llvm_unreachable("goto or switch was expected");
1507330f729Sjoerg }
1517330f729Sjoerg }
1527330f729Sjoerg }
1537330f729Sjoerg
1547330f729Sjoerg /// Checks the jump and stores each variable declaration it bypasses.
Detect(unsigned From,unsigned To)1557330f729Sjoerg void VarBypassDetector::Detect(unsigned From, unsigned To) {
1567330f729Sjoerg while (From != To) {
1577330f729Sjoerg if (From < To) {
1587330f729Sjoerg assert(Scopes[To].first < To);
1597330f729Sjoerg const auto &ScopeTo = Scopes[To];
1607330f729Sjoerg To = ScopeTo.first;
1617330f729Sjoerg Bypasses.insert(ScopeTo.second);
1627330f729Sjoerg } else {
1637330f729Sjoerg assert(Scopes[From].first < From);
1647330f729Sjoerg From = Scopes[From].first;
1657330f729Sjoerg }
1667330f729Sjoerg }
1677330f729Sjoerg }
168