xref: /netbsd-src/external/apache2/llvm/dist/clang/lib/CodeGen/VarBypassDetector.cpp (revision e038c9c4676b0f19b1b7dd08a940c6ed64a6d5ae)
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