1*0b57cec5SDimitry Andric //===--- VarBypassDetector.cpp - Bypass jumps detector ------------*- C++ -*-=//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric
9*0b57cec5SDimitry Andric #include "VarBypassDetector.h"
10*0b57cec5SDimitry Andric
11*0b57cec5SDimitry Andric #include "clang/AST/Decl.h"
12*0b57cec5SDimitry Andric #include "clang/AST/Expr.h"
13*0b57cec5SDimitry Andric #include "clang/AST/Stmt.h"
14*0b57cec5SDimitry Andric
15*0b57cec5SDimitry Andric using namespace clang;
16*0b57cec5SDimitry Andric using namespace CodeGen;
17*0b57cec5SDimitry Andric
18*0b57cec5SDimitry Andric /// Clear the object and pre-process for the given statement, usually function
19*0b57cec5SDimitry Andric /// body statement.
Init(const Stmt * Body)20*0b57cec5SDimitry Andric void VarBypassDetector::Init(const Stmt *Body) {
21*0b57cec5SDimitry Andric FromScopes.clear();
22*0b57cec5SDimitry Andric ToScopes.clear();
23*0b57cec5SDimitry Andric Bypasses.clear();
24*0b57cec5SDimitry Andric Scopes = {{~0U, nullptr}};
25*0b57cec5SDimitry Andric unsigned ParentScope = 0;
26*0b57cec5SDimitry Andric AlwaysBypassed = !BuildScopeInformation(Body, ParentScope);
27*0b57cec5SDimitry Andric if (!AlwaysBypassed)
28*0b57cec5SDimitry Andric Detect();
29*0b57cec5SDimitry Andric }
30*0b57cec5SDimitry Andric
31*0b57cec5SDimitry Andric /// Build scope information for a declaration that is part of a DeclStmt.
32*0b57cec5SDimitry Andric /// Returns false if we failed to build scope information and can't tell for
33*0b57cec5SDimitry Andric /// which vars are being bypassed.
BuildScopeInformation(const Decl * D,unsigned & ParentScope)34*0b57cec5SDimitry Andric bool VarBypassDetector::BuildScopeInformation(const Decl *D,
35*0b57cec5SDimitry Andric unsigned &ParentScope) {
36*0b57cec5SDimitry Andric const VarDecl *VD = dyn_cast<VarDecl>(D);
37*0b57cec5SDimitry Andric if (VD && VD->hasLocalStorage()) {
38*0b57cec5SDimitry Andric Scopes.push_back({ParentScope, VD});
39*0b57cec5SDimitry Andric ParentScope = Scopes.size() - 1;
40*0b57cec5SDimitry Andric }
41*0b57cec5SDimitry Andric
42*0b57cec5SDimitry Andric if (const VarDecl *VD = dyn_cast<VarDecl>(D))
43*0b57cec5SDimitry Andric if (const Expr *Init = VD->getInit())
44*0b57cec5SDimitry Andric return BuildScopeInformation(Init, ParentScope);
45*0b57cec5SDimitry Andric
46*0b57cec5SDimitry Andric return true;
47*0b57cec5SDimitry Andric }
48*0b57cec5SDimitry Andric
49*0b57cec5SDimitry Andric /// Walk through the statements, adding any labels or gotos to
50*0b57cec5SDimitry Andric /// LabelAndGotoScopes and recursively walking the AST as needed.
51*0b57cec5SDimitry Andric /// Returns false if we failed to build scope information and can't tell for
52*0b57cec5SDimitry Andric /// which vars are being bypassed.
BuildScopeInformation(const Stmt * S,unsigned & origParentScope)53*0b57cec5SDimitry Andric bool VarBypassDetector::BuildScopeInformation(const Stmt *S,
54*0b57cec5SDimitry Andric unsigned &origParentScope) {
55*0b57cec5SDimitry Andric // If this is a statement, rather than an expression, scopes within it don't
56*0b57cec5SDimitry Andric // propagate out into the enclosing scope. Otherwise we have to worry about
57*0b57cec5SDimitry Andric // block literals, which have the lifetime of their enclosing statement.
58*0b57cec5SDimitry Andric unsigned independentParentScope = origParentScope;
59*0b57cec5SDimitry Andric unsigned &ParentScope =
60*0b57cec5SDimitry Andric ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope
61*0b57cec5SDimitry Andric : independentParentScope);
62*0b57cec5SDimitry Andric
63*0b57cec5SDimitry Andric unsigned StmtsToSkip = 0u;
64*0b57cec5SDimitry Andric
65*0b57cec5SDimitry Andric switch (S->getStmtClass()) {
66*0b57cec5SDimitry Andric case Stmt::IndirectGotoStmtClass:
67*0b57cec5SDimitry Andric return false;
68*0b57cec5SDimitry Andric
69*0b57cec5SDimitry Andric case Stmt::SwitchStmtClass:
70*0b57cec5SDimitry Andric if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
71*0b57cec5SDimitry Andric if (!BuildScopeInformation(Init, ParentScope))
72*0b57cec5SDimitry Andric return false;
73*0b57cec5SDimitry Andric ++StmtsToSkip;
74*0b57cec5SDimitry Andric }
75*0b57cec5SDimitry Andric if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
76*0b57cec5SDimitry Andric if (!BuildScopeInformation(Var, ParentScope))
77*0b57cec5SDimitry Andric return false;
78*0b57cec5SDimitry Andric ++StmtsToSkip;
79*0b57cec5SDimitry Andric }
80*0b57cec5SDimitry Andric [[fallthrough]];
81*0b57cec5SDimitry Andric
82*0b57cec5SDimitry Andric case Stmt::GotoStmtClass:
83*0b57cec5SDimitry Andric FromScopes.push_back({S, ParentScope});
84*0b57cec5SDimitry Andric break;
85*0b57cec5SDimitry Andric
86*0b57cec5SDimitry Andric case Stmt::DeclStmtClass: {
87*0b57cec5SDimitry Andric const DeclStmt *DS = cast<DeclStmt>(S);
88*0b57cec5SDimitry Andric for (auto *I : DS->decls())
89*0b57cec5SDimitry Andric if (!BuildScopeInformation(I, origParentScope))
90*0b57cec5SDimitry Andric return false;
91*0b57cec5SDimitry Andric return true;
92*0b57cec5SDimitry Andric }
93*0b57cec5SDimitry Andric
94*0b57cec5SDimitry Andric case Stmt::CaseStmtClass:
95*0b57cec5SDimitry Andric case Stmt::DefaultStmtClass:
96*0b57cec5SDimitry Andric case Stmt::LabelStmtClass:
97*0b57cec5SDimitry Andric llvm_unreachable("the loop below handles labels and cases");
98*0b57cec5SDimitry Andric break;
99*0b57cec5SDimitry Andric
100*0b57cec5SDimitry Andric default:
101*0b57cec5SDimitry Andric break;
102*0b57cec5SDimitry Andric }
103*0b57cec5SDimitry Andric
104*0b57cec5SDimitry Andric for (const Stmt *SubStmt : S->children()) {
105*0b57cec5SDimitry Andric if (!SubStmt)
106*0b57cec5SDimitry Andric continue;
107*0b57cec5SDimitry Andric if (StmtsToSkip) {
108*0b57cec5SDimitry Andric --StmtsToSkip;
109*0b57cec5SDimitry Andric continue;
110*0b57cec5SDimitry Andric }
111*0b57cec5SDimitry Andric
112*0b57cec5SDimitry Andric // Cases, labels, and defaults aren't "scope parents". It's also
113*0b57cec5SDimitry Andric // important to handle these iteratively instead of recursively in
114*0b57cec5SDimitry Andric // order to avoid blowing out the stack.
115*0b57cec5SDimitry Andric while (true) {
116*0b57cec5SDimitry Andric const Stmt *Next;
117*0b57cec5SDimitry Andric if (const SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt))
118*0b57cec5SDimitry Andric Next = SC->getSubStmt();
119*0b57cec5SDimitry Andric else if (const LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
120*0b57cec5SDimitry Andric Next = LS->getSubStmt();
121*0b57cec5SDimitry Andric else
122*0b57cec5SDimitry Andric break;
123*0b57cec5SDimitry Andric
124*0b57cec5SDimitry Andric ToScopes[SubStmt] = ParentScope;
125*0b57cec5SDimitry Andric SubStmt = Next;
126*0b57cec5SDimitry Andric }
127*0b57cec5SDimitry Andric
128*0b57cec5SDimitry Andric // Recursively walk the AST.
129*0b57cec5SDimitry Andric if (!BuildScopeInformation(SubStmt, ParentScope))
130*0b57cec5SDimitry Andric return false;
131*0b57cec5SDimitry Andric }
132*0b57cec5SDimitry Andric return true;
133*0b57cec5SDimitry Andric }
134*0b57cec5SDimitry Andric
135*0b57cec5SDimitry Andric /// Checks each jump and stores each variable declaration they bypass.
Detect()136*0b57cec5SDimitry Andric void VarBypassDetector::Detect() {
137*0b57cec5SDimitry Andric for (const auto &S : FromScopes) {
138*0b57cec5SDimitry Andric const Stmt *St = S.first;
139*0b57cec5SDimitry Andric unsigned from = S.second;
140*0b57cec5SDimitry Andric if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) {
141*0b57cec5SDimitry Andric if (const LabelStmt *LS = GS->getLabel()->getStmt())
142*0b57cec5SDimitry Andric Detect(from, ToScopes[LS]);
143*0b57cec5SDimitry Andric } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) {
144*0b57cec5SDimitry Andric for (const SwitchCase *SC = SS->getSwitchCaseList(); SC;
145*0b57cec5SDimitry Andric SC = SC->getNextSwitchCase()) {
146*0b57cec5SDimitry Andric Detect(from, ToScopes[SC]);
147*0b57cec5SDimitry Andric }
148*0b57cec5SDimitry Andric } else {
149*0b57cec5SDimitry Andric llvm_unreachable("goto or switch was expected");
150*0b57cec5SDimitry Andric }
151*0b57cec5SDimitry Andric }
152*0b57cec5SDimitry Andric }
153*0b57cec5SDimitry Andric
154*0b57cec5SDimitry Andric /// Checks the jump and stores each variable declaration it bypasses.
Detect(unsigned From,unsigned To)155*0b57cec5SDimitry Andric void VarBypassDetector::Detect(unsigned From, unsigned To) {
156*0b57cec5SDimitry Andric while (From != To) {
157*0b57cec5SDimitry Andric if (From < To) {
158*0b57cec5SDimitry Andric assert(Scopes[To].first < To);
159*0b57cec5SDimitry Andric const auto &ScopeTo = Scopes[To];
160*0b57cec5SDimitry Andric To = ScopeTo.first;
161*0b57cec5SDimitry Andric Bypasses.insert(ScopeTo.second);
162*0b57cec5SDimitry Andric } else {
163*0b57cec5SDimitry Andric assert(Scopes[From].first < From);
164*0b57cec5SDimitry Andric From = Scopes[From].first;
165*0b57cec5SDimitry Andric }
166*0b57cec5SDimitry Andric }
167*0b57cec5SDimitry Andric }
168