xref: /freebsd-src/contrib/llvm-project/clang/lib/CodeGen/VarBypassDetector.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1fe6060f1SDimitry Andric //===--- VarBypassDetector.cpp - Bypass jumps detector ------------*- C++ -*-=//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "VarBypassDetector.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "clang/AST/Decl.h"
120b57cec5SDimitry Andric #include "clang/AST/Expr.h"
130b57cec5SDimitry Andric #include "clang/AST/Stmt.h"
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric using namespace clang;
160b57cec5SDimitry Andric using namespace CodeGen;
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric /// Clear the object and pre-process for the given statement, usually function
190b57cec5SDimitry Andric /// body statement.
Init(const Stmt * Body)200b57cec5SDimitry Andric void VarBypassDetector::Init(const Stmt *Body) {
210b57cec5SDimitry Andric   FromScopes.clear();
220b57cec5SDimitry Andric   ToScopes.clear();
230b57cec5SDimitry Andric   Bypasses.clear();
240b57cec5SDimitry Andric   Scopes = {{~0U, nullptr}};
250b57cec5SDimitry Andric   unsigned ParentScope = 0;
260b57cec5SDimitry Andric   AlwaysBypassed = !BuildScopeInformation(Body, ParentScope);
270b57cec5SDimitry Andric   if (!AlwaysBypassed)
280b57cec5SDimitry Andric     Detect();
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric /// Build scope information for a declaration that is part of a DeclStmt.
320b57cec5SDimitry Andric /// Returns false if we failed to build scope information and can't tell for
330b57cec5SDimitry Andric /// which vars are being bypassed.
BuildScopeInformation(const Decl * D,unsigned & ParentScope)340b57cec5SDimitry Andric bool VarBypassDetector::BuildScopeInformation(const Decl *D,
350b57cec5SDimitry Andric                                               unsigned &ParentScope) {
360b57cec5SDimitry Andric   const VarDecl *VD = dyn_cast<VarDecl>(D);
370b57cec5SDimitry Andric   if (VD && VD->hasLocalStorage()) {
380b57cec5SDimitry Andric     Scopes.push_back({ParentScope, VD});
390b57cec5SDimitry Andric     ParentScope = Scopes.size() - 1;
400b57cec5SDimitry Andric   }
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   if (const VarDecl *VD = dyn_cast<VarDecl>(D))
430b57cec5SDimitry Andric     if (const Expr *Init = VD->getInit())
440b57cec5SDimitry Andric       return BuildScopeInformation(Init, ParentScope);
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   return true;
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric /// Walk through the statements, adding any labels or gotos to
500b57cec5SDimitry Andric /// LabelAndGotoScopes and recursively walking the AST as needed.
510b57cec5SDimitry Andric /// Returns false if we failed to build scope information and can't tell for
520b57cec5SDimitry Andric /// which vars are being bypassed.
BuildScopeInformation(const Stmt * S,unsigned & origParentScope)530b57cec5SDimitry Andric bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
540b57cec5SDimitry Andric                                               unsigned &origParentScope) {
550b57cec5SDimitry Andric   // If this is a statement, rather than an expression, scopes within it don't
560b57cec5SDimitry Andric   // propagate out into the enclosing scope. Otherwise we have to worry about
570b57cec5SDimitry Andric   // block literals, which have the lifetime of their enclosing statement.
580b57cec5SDimitry Andric   unsigned independentParentScope = origParentScope;
590b57cec5SDimitry Andric   unsigned &ParentScope =
600b57cec5SDimitry Andric       ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope
610b57cec5SDimitry Andric                                            : independentParentScope);
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   unsigned StmtsToSkip = 0u;
640b57cec5SDimitry Andric 
650b57cec5SDimitry Andric   switch (S->getStmtClass()) {
660b57cec5SDimitry Andric   case Stmt::IndirectGotoStmtClass:
670b57cec5SDimitry Andric     return false;
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   case Stmt::SwitchStmtClass:
700b57cec5SDimitry Andric     if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
710b57cec5SDimitry Andric       if (!BuildScopeInformation(Init, ParentScope))
720b57cec5SDimitry Andric         return false;
730b57cec5SDimitry Andric       ++StmtsToSkip;
740b57cec5SDimitry Andric     }
750b57cec5SDimitry Andric     if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
760b57cec5SDimitry Andric       if (!BuildScopeInformation(Var, ParentScope))
770b57cec5SDimitry Andric         return false;
780b57cec5SDimitry Andric       ++StmtsToSkip;
790b57cec5SDimitry Andric     }
80*bdd1243dSDimitry Andric     [[fallthrough]];
810b57cec5SDimitry Andric 
820b57cec5SDimitry Andric   case Stmt::GotoStmtClass:
830b57cec5SDimitry Andric     FromScopes.push_back({S, ParentScope});
840b57cec5SDimitry Andric     break;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   case Stmt::DeclStmtClass: {
870b57cec5SDimitry Andric     const DeclStmt *DS = cast<DeclStmt>(S);
880b57cec5SDimitry Andric     for (auto *I : DS->decls())
890b57cec5SDimitry Andric       if (!BuildScopeInformation(I, origParentScope))
900b57cec5SDimitry Andric         return false;
910b57cec5SDimitry Andric     return true;
920b57cec5SDimitry Andric   }
930b57cec5SDimitry Andric 
940b57cec5SDimitry Andric   case Stmt::CaseStmtClass:
950b57cec5SDimitry Andric   case Stmt::DefaultStmtClass:
960b57cec5SDimitry Andric   case Stmt::LabelStmtClass:
970b57cec5SDimitry Andric     llvm_unreachable("the loop below handles labels and cases");
980b57cec5SDimitry Andric     break;
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   default:
1010b57cec5SDimitry Andric     break;
1020b57cec5SDimitry Andric   }
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   for (const Stmt *SubStmt : S->children()) {
1050b57cec5SDimitry Andric     if (!SubStmt)
1060b57cec5SDimitry Andric       continue;
1070b57cec5SDimitry Andric     if (StmtsToSkip) {
1080b57cec5SDimitry Andric       --StmtsToSkip;
1090b57cec5SDimitry Andric       continue;
1100b57cec5SDimitry Andric     }
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric     // Cases, labels, and defaults aren't "scope parents".  It's also
1130b57cec5SDimitry Andric     // important to handle these iteratively instead of recursively in
1140b57cec5SDimitry Andric     // order to avoid blowing out the stack.
1150b57cec5SDimitry Andric     while (true) {
1160b57cec5SDimitry Andric       const Stmt *Next;
1170b57cec5SDimitry Andric       if (const SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))
1180b57cec5SDimitry Andric         Next = SC->getSubStmt();
1190b57cec5SDimitry Andric       else if (const LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
1200b57cec5SDimitry Andric         Next = LS->getSubStmt();
1210b57cec5SDimitry Andric       else
1220b57cec5SDimitry Andric         break;
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric       ToScopes[SubStmt] = ParentScope;
1250b57cec5SDimitry Andric       SubStmt = Next;
1260b57cec5SDimitry Andric     }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric     // Recursively walk the AST.
1290b57cec5SDimitry Andric     if (!BuildScopeInformation(SubStmt, ParentScope))
1300b57cec5SDimitry Andric       return false;
1310b57cec5SDimitry Andric   }
1320b57cec5SDimitry Andric   return true;
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric /// Checks each jump and stores each variable declaration they bypass.
Detect()1360b57cec5SDimitry Andric void VarBypassDetector::Detect() {
1370b57cec5SDimitry Andric   for (const auto &S : FromScopes) {
1380b57cec5SDimitry Andric     const Stmt *St = S.first;
1390b57cec5SDimitry Andric     unsigned from = S.second;
1400b57cec5SDimitry Andric     if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) {
1410b57cec5SDimitry Andric       if (const LabelStmt *LS = GS->getLabel()->getStmt())
1420b57cec5SDimitry Andric         Detect(from, ToScopes[LS]);
1430b57cec5SDimitry Andric     } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) {
1440b57cec5SDimitry Andric       for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
1450b57cec5SDimitry Andric            SC = SC->getNextSwitchCase()) {
1460b57cec5SDimitry Andric         Detect(from, ToScopes[SC]);
1470b57cec5SDimitry Andric       }
1480b57cec5SDimitry Andric     } else {
1490b57cec5SDimitry Andric       llvm_unreachable("goto or switch was expected");
1500b57cec5SDimitry Andric     }
1510b57cec5SDimitry Andric   }
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric /// Checks the jump and stores each variable declaration it bypasses.
Detect(unsigned From,unsigned To)1550b57cec5SDimitry Andric void VarBypassDetector::Detect(unsigned From, unsigned To) {
1560b57cec5SDimitry Andric   while (From != To) {
1570b57cec5SDimitry Andric     if (From < To) {
1580b57cec5SDimitry Andric       assert(Scopes[To].first < To);
1590b57cec5SDimitry Andric       const auto &ScopeTo = Scopes[To];
1600b57cec5SDimitry Andric       To = ScopeTo.first;
1610b57cec5SDimitry Andric       Bypasses.insert(ScopeTo.second);
1620b57cec5SDimitry Andric     } else {
1630b57cec5SDimitry Andric       assert(Scopes[From].first < From);
1640b57cec5SDimitry Andric       From = Scopes[From].first;
1650b57cec5SDimitry Andric     }
1660b57cec5SDimitry Andric   }
1670b57cec5SDimitry Andric }
168