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 "clang_compatibility.h"
38 #include "killed_locals.h"
41 using namespace clang
;
43 /* Return the file offset of the expansion location of "Loc".
45 static unsigned getExpansionOffset(SourceManager
&SM
, SourceLocation Loc
)
47 return SM
.getFileOffset(SM
.getExpansionLoc(Loc
));
50 /* Given a DeclRefExpr or an ArraySubscriptExpr, return a pointer
51 * to the base DeclRefExpr.
52 * If the expression is something other than a nested ArraySubscriptExpr
53 * with a DeclRefExpr at the base, then return NULL.
55 static DeclRefExpr
*extract_array_base(Expr
*expr
)
57 while (isa
<ArraySubscriptExpr
>(expr
)) {
58 expr
= (cast
<ArraySubscriptExpr
>(expr
))->getBase();
59 expr
= pet_clang_strip_casts(expr
);
61 return dyn_cast
<DeclRefExpr
>(expr
);
64 /* Add "decl" to the set of local variables, provided it is a ValueDecl.
66 void pet_killed_locals::add_local(Decl
*decl
)
70 vd
= dyn_cast
<ValueDecl
>(decl
);
75 /* Add all variables declared by "stmt" to the set of local variables.
77 void pet_killed_locals::add_locals(DeclStmt
*stmt
)
79 if (stmt
->isSingleDecl()) {
80 add_local(stmt
->getSingleDecl());
82 const DeclGroup
&group
= stmt
->getDeclGroup().getDeclGroup();
83 unsigned n
= group
.size();
84 for (unsigned i
= 0; i
< n
; ++i
)
89 /* Set this->addr_end to the end of the address_of expression "expr".
91 void pet_killed_locals::set_addr_end(UnaryOperator
*expr
)
93 addr_end
= getExpansionOffset(SM
, end_loc(expr
));
96 /* Given an expression of type ArraySubscriptExpr or DeclRefExpr,
98 * - is the variable used inside the scop?
99 * - is the variable used after the scop or can a pointer be taken?
100 * Return true if the traversal should continue.
102 * Reset the pointer to the end of the latest address-of expression
103 * such that only the first array or scalar is considered to have
104 * its address taken. In particular, accesses inside the indices
105 * of the array should not be considered to have their address taken.
107 * If the variable is not one of the local variables or
108 * if the access appears inside an expression that was already handled,
109 * then simply return.
111 * Otherwise, the expression is handled and "expr_end" is updated
112 * to prevent subexpressions with the same base expression
113 * from being handled as well.
115 * If a higher-dimensional slice of an array is accessed or
116 * if the access appears inside an address-of expression,
117 * then a pointer may leak, so the variable should not be killed.
118 * Similarly, if the access appears after the end of the scop,
119 * then the variable should not be killed.
121 * Otherwise, if the access appears inside the scop, then
122 * keep track of the fact that the variable was accessed at least once
125 bool pet_killed_locals::check_decl_in_expr(Expr
*expr
)
131 unsigned old_addr_end
;
133 ref
= extract_array_base(expr
);
137 old_addr_end
= addr_end
;
140 decl
= ref
->getDecl();
141 if (locals
.find(decl
) == locals
.end())
143 loc
= getExpansionOffset(SM
, begin_loc(expr
));
147 expr_end
= getExpansionOffset(SM
, end_loc(ref
));
148 depth
= pet_clang_array_depth(expr
->getType());
149 if (loc
>= scop_end
|| loc
<= old_addr_end
|| depth
!= 0)
151 if (loc
>= scop_start
&& loc
<= scop_end
)
152 accessed
.insert(decl
);
154 return locals
.size() != 0;
157 /* Remove the local variables that may be accessed inside "stmt" after
158 * the scop starting at "start" and ending at "end", or that
159 * are not accessed at all inside that scop.
161 * If there are no local variables that could potentially be killed,
162 * then simply return.
164 * Otherwise, scan "stmt" for any potential use of the variables
165 * after the scop. This includes a possible pointer being taken
166 * to (part of) the variable. If there is any such use, then
167 * the variable is removed from the set of local variables.
169 * At the same time, keep track of the variables that are
170 * used anywhere inside the scop. At the end, replace the local
171 * variables with the intersection with these accessed variables.
173 void pet_killed_locals::remove_accessed_after(Stmt
*stmt
, unsigned start
,
176 set
<ValueDecl
*> accessed_local
;
178 if (locals
.size() == 0)
185 set_intersection(locals
.begin(), locals
.end(),
186 accessed
.begin(), accessed
.end(),
187 inserter(accessed_local
, accessed_local
.begin()));
188 locals
= accessed_local
;