1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | #include "VarBypassDetector.h" |
10 | |
11 | #include "clang/AST/Decl.h" |
12 | #include "clang/AST/Expr.h" |
13 | #include "clang/AST/Stmt.h" |
14 | |
15 | using namespace clang; |
16 | using namespace CodeGen; |
17 | |
18 | |
19 | |
20 | void VarBypassDetector::Init(const Stmt *Body) { |
21 | FromScopes.clear(); |
22 | ToScopes.clear(); |
23 | Bypasses.clear(); |
24 | Scopes = {{~0U, nullptr}}; |
25 | unsigned ParentScope = 0; |
26 | AlwaysBypassed = !BuildScopeInformation(Body, ParentScope); |
27 | if (!AlwaysBypassed) |
28 | Detect(); |
29 | } |
30 | |
31 | |
32 | |
33 | |
34 | bool VarBypassDetector::BuildScopeInformation(const Decl *D, |
35 | unsigned &ParentScope) { |
36 | const VarDecl *VD = dyn_cast<VarDecl>(D); |
37 | if (VD && VD->hasLocalStorage()) { |
38 | Scopes.push_back({ParentScope, VD}); |
39 | ParentScope = Scopes.size() - 1; |
40 | } |
41 | |
42 | if (const VarDecl *VD = dyn_cast<VarDecl>(D)) |
43 | if (const Expr *Init = VD->getInit()) |
44 | return BuildScopeInformation(Init, ParentScope); |
45 | |
46 | return true; |
47 | } |
48 | |
49 | |
50 | |
51 | |
52 | |
53 | bool VarBypassDetector::BuildScopeInformation(const Stmt *S, |
54 | unsigned &origParentScope) { |
55 | |
56 | |
57 | |
58 | unsigned independentParentScope = origParentScope; |
59 | unsigned &ParentScope = |
60 | ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope |
61 | : independentParentScope); |
62 | |
63 | unsigned StmtsToSkip = 0u; |
64 | |
65 | switch (S->getStmtClass()) { |
66 | case Stmt::IndirectGotoStmtClass: |
67 | return false; |
68 | |
69 | case Stmt::SwitchStmtClass: |
70 | if (const Stmt *Init = cast<SwitchStmt>(S)->getInit()) { |
71 | if (!BuildScopeInformation(Init, ParentScope)) |
72 | return false; |
73 | ++StmtsToSkip; |
74 | } |
75 | if (const VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) { |
76 | if (!BuildScopeInformation(Var, ParentScope)) |
77 | return false; |
78 | ++StmtsToSkip; |
79 | } |
80 | LLVM_FALLTHROUGH; |
81 | |
82 | case Stmt::GotoStmtClass: |
83 | FromScopes.push_back({S, ParentScope}); |
84 | break; |
85 | |
86 | case Stmt::DeclStmtClass: { |
87 | const DeclStmt *DS = cast<DeclStmt>(S); |
88 | for (auto *I : DS->decls()) |
89 | if (!BuildScopeInformation(I, origParentScope)) |
90 | return false; |
91 | return true; |
92 | } |
93 | |
94 | case Stmt::CaseStmtClass: |
95 | case Stmt::DefaultStmtClass: |
96 | case Stmt::LabelStmtClass: |
97 | llvm_unreachable("the loop below handles labels and cases"); |
98 | break; |
99 | |
100 | default: |
101 | break; |
102 | } |
103 | |
104 | for (const Stmt *SubStmt : S->children()) { |
105 | if (!SubStmt) |
106 | continue; |
107 | if (StmtsToSkip) { |
108 | --StmtsToSkip; |
109 | continue; |
110 | } |
111 | |
112 | |
113 | |
114 | |
115 | while (true) { |
116 | const Stmt *Next; |
117 | if (const SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt)) |
118 | Next = SC->getSubStmt(); |
119 | else if (const LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt)) |
120 | Next = LS->getSubStmt(); |
121 | else |
122 | break; |
123 | |
124 | ToScopes[SubStmt] = ParentScope; |
125 | SubStmt = Next; |
126 | } |
127 | |
128 | |
129 | if (!BuildScopeInformation(SubStmt, ParentScope)) |
130 | return false; |
131 | } |
132 | return true; |
133 | } |
134 | |
135 | |
136 | void VarBypassDetector::Detect() { |
137 | for (const auto &S : FromScopes) { |
138 | const Stmt *St = S.first; |
139 | unsigned from = S.second; |
140 | if (const GotoStmt *GS = dyn_cast<GotoStmt>(St)) { |
141 | if (const LabelStmt *LS = GS->getLabel()->getStmt()) |
142 | Detect(from, ToScopes[LS]); |
143 | } else if (const SwitchStmt *SS = dyn_cast<SwitchStmt>(St)) { |
144 | for (const SwitchCase *SC = SS->getSwitchCaseList(); SC; |
145 | SC = SC->getNextSwitchCase()) { |
146 | Detect(from, ToScopes[SC]); |
147 | } |
148 | } else { |
149 | llvm_unreachable("goto or switch was expected"); |
150 | } |
151 | } |
152 | } |
153 | |
154 | |
155 | void VarBypassDetector::Detect(unsigned From, unsigned To) { |
156 | while (From != To) { |
157 | if (From < To) { |
158 | assert(Scopes[To].first < To); |
159 | const auto &ScopeTo = Scopes[To]; |
160 | To = ScopeTo.first; |
161 | Bypasses.insert(ScopeTo.second); |
162 | } else { |
163 | assert(Scopes[From].first < From); |
164 | From = Scopes[From].first; |
165 | } |
166 | } |
167 | } |
168 | |