Coverage Report

Created: 2019-07-24 05:18

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