2 * Copyright 2015 Sven Verdoolaege. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY SVEN VERDOOLAEGE ''AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
37 #include "killed_locals.h"
40 using namespace clang
;
42 /* Return the file offset of the expansion location of "Loc".
44 static unsigned getExpansionOffset(SourceManager
&SM
, SourceLocation Loc
)
46 return SM
.getFileOffset(SM
.getExpansionLoc(Loc
));
49 /* Given a DeclRefExpr or an ArraySubscriptExpr, return a pointer
50 * to the base DeclRefExpr.
51 * If the expression is something other than a nested ArraySubscriptExpr
52 * with a DeclRefExpr at the base, then return NULL.
54 static DeclRefExpr
*extract_array_base(Expr
*expr
)
56 while (isa
<ArraySubscriptExpr
>(expr
)) {
57 expr
= (cast
<ArraySubscriptExpr
>(expr
))->getBase();
58 expr
= pet_clang_strip_casts(expr
);
60 return dyn_cast
<DeclRefExpr
>(expr
);
63 /* Add "decl" to the set of local variables, provided it is a ValueDecl.
65 void pet_killed_locals::add_local(Decl
*decl
)
69 vd
= dyn_cast
<ValueDecl
>(decl
);
74 /* Add all variables declared by "stmt" to the set of local variables.
76 void pet_killed_locals::add_locals(DeclStmt
*stmt
)
78 if (stmt
->isSingleDecl()) {
79 add_local(stmt
->getSingleDecl());
81 const DeclGroup
&group
= stmt
->getDeclGroup().getDeclGroup();
82 unsigned n
= group
.size();
83 for (unsigned i
= 0; i
< n
; ++i
)
88 /* Set this->addr_end to the end of the address_of expression "expr".
90 void pet_killed_locals::set_addr_end(UnaryOperator
*expr
)
92 addr_end
= getExpansionOffset(SM
, expr
->getLocEnd());
95 /* Given an expression of type ArraySubscriptExpr or DeclRefExpr,
97 * - is the variable used inside the scop?
98 * - is the variable used after the scop or can a pointer be taken?
99 * Return true if the traversal should continue.
101 * Reset the pointer to the end of the latest address-of expression
102 * such that only the first array or scalar is considered to have
103 * its address taken. In particular, accesses inside the indices
104 * of the array should not be considered to have their address taken.
106 * If the variable is not one of the local variables or
107 * if the access appears inside an expression that was already handled,
108 * then simply return.
110 * Otherwise, the expression is handled and "expr_end" is updated
111 * to prevent subexpressions with the same base expression
112 * from being handled as well.
114 * If a higher-dimensional slice of an array is accessed or
115 * if the access appears inside an address-of expression,
116 * then a pointer may leak, so the variable should not be killed.
117 * Similarly, if the access appears after the end of the scop,
118 * then the variable should not be killed.
120 * Otherwise, if the access appears inside the scop, then
121 * keep track of the fact that the variable was accessed at least once
124 bool pet_killed_locals::check_decl_in_expr(Expr
*expr
)
130 unsigned old_addr_end
;
132 ref
= extract_array_base(expr
);
136 old_addr_end
= addr_end
;
139 decl
= ref
->getDecl();
140 if (locals
.find(decl
) == locals
.end())
142 loc
= getExpansionOffset(SM
, expr
->getLocStart());
146 expr_end
= getExpansionOffset(SM
, ref
->getLocEnd());
147 depth
= pet_clang_array_depth(expr
->getType());
148 if (loc
>= scop_end
|| loc
<= old_addr_end
|| depth
!= 0)
150 if (loc
>= scop_start
&& loc
<= scop_end
)
151 accessed
.insert(decl
);
153 return locals
.size() != 0;
156 /* Remove the local variables that may be accessed inside "stmt" after
157 * the scop starting at "start" and ending at "end", or that
158 * are not accessed at all inside that scop.
160 * If there are no local variables that could potentially be killed,
161 * then simply return.
163 * Otherwise, scan "stmt" for any potential use of the variables
164 * after the scop. This includes a possible pointer being taken
165 * to (part of) the variable. If there is any such use, then
166 * the variable is removed from the set of local variables.
168 * At the same time, keep track of the variables that are
169 * used anywhere inside the scop. At the end, replace the local
170 * variables with the intersection with these accessed variables.
172 void pet_killed_locals::remove_accessed_after(Stmt
*stmt
, unsigned start
,
175 set
<ValueDecl
*> accessed_local
;
177 if (locals
.size() == 0)
184 set_intersection(locals
.begin(), locals
.end(),
185 accessed
.begin(), accessed
.end(),
186 inserter(accessed_local
, accessed_local
.begin()));
187 locals
= accessed_local
;