1 // -*- mode: C++ -*-
2 //
3 // Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, 2014, 2015, 2016, 2017 The University of Utah
4 // All rights reserved.
5 //
6 // This file is part of `csmith', a random generator of C programs.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are met:
10 //
11 // * Redistributions of source code must retain the above copyright notice,
12 // this list of conditions and the following disclaimer.
13 //
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29
30 #if HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #include "StatementArrayOp.h"
35 #include <cassert>
36
37 #include "Common.h"
38 #include "CGContext.h"
39 #include "CGOptions.h"
40
41 #include "ArrayVariable.h"
42 #include "Block.h"
43 #include "CFGEdge.h"
44 #include "Effect.h"
45 #include "Error.h"
46 #include "Expression.h"
47 #include "FactMgr.h"
48 #include "Function.h"
49 #include "Lhs.h"
50 #include "StatementFor.h"
51 #include "Type.h"
52 #include "Variable.h"
53 #include "VariableSelector.h"
54 #include "random.h"
55 #include "util.h"
56
57 using namespace std;
58
59 ///////////////////////////////////////////////////////////////////////////////
60
61 /*
62 * Randomly determine the iteration over an array: initial value,
63 * increment value (negative means going backwards), given the size
64 * of array
65 */
66 void
make_random_iter_ctrl(int size,int & init,int & incr)67 StatementArrayOp::make_random_iter_ctrl(int size, int &init, int &incr)
68 {
69 // We don't have to put error guards here because we are trying
70 // to get pure random numbers, and in this case, we cannot get
71 // errors
72 init = pure_rnd_flipcoin(50) ? 0 : pure_rnd_upto(size);
73 incr = pure_rnd_flipcoin(50) ? 1 : pure_rnd_upto(size) + 1;
74 }
75
76 /*
77 *
78 */
79 Statement*
make_random(CGContext & cg_context)80 StatementArrayOp::make_random(CGContext &cg_context)
81 {
82 bool ary_init = rnd_flipcoin(5);
83 ERROR_GUARD(NULL);
84 if (ary_init) {
85 return make_random_array_init(cg_context);
86 }
87 StatementFor* sf = StatementFor::make_random_array_loop(cg_context);
88 return sf;
89 }
90
91 StatementArrayOp *
make_random_array_init(CGContext & cg_context)92 StatementArrayOp::make_random_array_init(CGContext &cg_context)
93 {
94 // select the array to initialize
95 //static int g = 0;
96 //int h = g++;
97 ArrayVariable* av = VariableSelector::select_array(cg_context);
98 ERROR_GUARD(NULL);
99 cg_context.get_effect_stm().clear();
100 // Select the loop control variable.
101 vector<const Variable*> invalid_vars;
102 vector<const Variable*> cvs;
103 ERROR_GUARD(NULL);
104 // the iteration settings are simple: start from index 0, step through all members
105 vector<int> inits, incrs;
106 size_t i;
107 cg_context.get_effect_stm().clear();
108 FactMgr* fm = get_fact_mgr(&cg_context);
109 int vol_count = 0;
110 if (av->is_volatile())
111 vol_count++;
112
113 for (i=0; i<av->get_dimension(); i++) {
114 inits.push_back(0);
115 incrs.push_back(1);
116 Variable *cv = NULL;
117 do {
118 cv = VariableSelector::SelectLoopCtrlVar(cg_context, invalid_vars);
119 if (cv->type->is_float()) {
120 invalid_vars.push_back(cv);
121 continue;
122 }
123 if (cv->is_volatile())
124 vol_count++;
125 if ((CGOptions::strict_volatile_rule() && (vol_count > 1) && cv->is_volatile())
126 || (CGOptions::ccomp() && cv->is_packed_aggregate_field_var())
127 || (!CGOptions::signed_char_index() && cv->type->is_signed_char())) {
128 invalid_vars.push_back(cv);
129 continue;
130 }
131 else {
132 break;
133 }
134 } while (true);
135 invalid_vars.push_back(cv);
136 cvs.push_back(cv);
137 bool read = cg_context.read_indices(cv, fm->global_facts);
138 assert(read);
139 cg_context.write_var(cv);
140 // put in induction variable list so that later indices have no write-write conflict
141 cg_context.iv_bounds[cv] = av->get_sizes()[i];
142 }
143 cg_context.write_var(av);
144
145 // JYTODO: initialize only field(s) of array members if they are of type struct
146 Block* b = cg_context.get_current_block()->random_parent_block();
147 Expression* init = VariableSelector::make_init_value(Effect::READ, cg_context, av->type, &av->qfer, b);
148 assert(init->visit_facts(fm->global_facts, cg_context));
149 StatementArrayOp* sa = new StatementArrayOp(cg_context.get_current_block(), av, cvs, inits, incrs, init);
150 Lhs lhs(*av);
151 if (FactMgr::update_fact_for_assign(&lhs, init, fm->global_facts)) {
152 cg_context.get_current_func()->fact_changed = true;
153 }
154 fm->map_stm_effect[sa] = cg_context.get_effect_stm();
155
156 // clear IV list from cg_context
157 for (i=0; i<cvs.size(); i++) {
158 cg_context.iv_bounds.erase(cvs[i]);
159 }
160 return sa;
161 }
162
163 /*
164 *
165 */
StatementArrayOp(Block * b,const ArrayVariable * av,const std::vector<const Variable * > & cvs,const std::vector<int> & inits,const std::vector<int> & incrs,const Block * body)166 StatementArrayOp::StatementArrayOp(Block* b, const ArrayVariable* av,
167 const std::vector<const Variable*>& cvs,
168 const std::vector<int>& inits,
169 const std::vector<int>& incrs,
170 const Block *body)
171 : Statement(eArrayOp, b),
172 array_var(av),
173 ctrl_vars(cvs),
174 inits(inits),
175 incrs(incrs),
176 body(body),
177 init_value(0)
178 {
179 // Nothing else to do.
180 }
181
182 /*
183 *
184 */
StatementArrayOp(Block * b,const ArrayVariable * av,const std::vector<const Variable * > & cvs,const std::vector<int> & inits,const std::vector<int> & incrs,const Expression * e)185 StatementArrayOp::StatementArrayOp(Block* b, const ArrayVariable* av,
186 const std::vector<const Variable*>& cvs,
187 const std::vector<int>& inits,
188 const std::vector<int>& incrs,
189 const Expression *e)
190 : Statement(eArrayOp, b),
191 array_var(av),
192 ctrl_vars(cvs),
193 inits(inits),
194 incrs(incrs),
195 body(0),
196 init_value(e)
197 {
198 // Nothing else to do.
199 }
200
201 /*
202 *
203 */
~StatementArrayOp(void)204 StatementArrayOp::~StatementArrayOp(void)
205 {
206 delete init_value;
207 delete body;
208 }
209
210 void
output_header(std::ostream & out,int & indent) const211 StatementArrayOp::output_header(std::ostream& out, int& indent) const
212 {
213 size_t i;
214 for (i=0; i<array_var->get_dimension(); i++) {
215 if (i > 0) {
216 output_tab(out, indent);
217 out << "{";
218 outputln(out);
219 indent++;
220 }
221 output_tab(out, indent);
222 out << "for (";
223 ctrl_vars[i]->Output(out);
224 out << " = " << inits[i] << "; ";
225 ctrl_vars[i]->Output(out);
226 (incrs[i] > 0) ? out << " < " << array_var->get_sizes()[i] : out << " >= 0";
227 out << "; ";
228 ctrl_vars[i]->Output(out);
229 if (CGOptions::ccomp()) {
230 // ccomp disable something like g += 1, where g is volatile
231 out << " = ";
232 ctrl_vars[i]->Output(out);
233 out << " + " << incrs[i] << ")";
234 }
235 else {
236 out << " += " << incrs[i] << ")";
237 }
238 outputln(out);
239 }
240 }
241
242 /*
243 *
244 */
245 void
Output(std::ostream & out,FactMgr * fm,int indent) const246 StatementArrayOp::Output(std::ostream &out, FactMgr* fm, int indent) const
247 {
248 size_t i;
249 output_header(out, indent);
250
251 if (body) {
252 body->Output(out, fm, indent);
253 }
254 else if (init_value) {
255 output_tab(out, indent);
256 out << "{";
257 outputln(out);
258 // cannot assign array members to a struct/union constant directly, has to create a "fake" struct var first
259 if (init_value->term_type == eConstant && array_var->is_aggregate()) {
260 output_tab(out, indent+1);
261 array_var->type->Output(out);
262 out << " tmp = ";
263 init_value->Output(out);
264 out << ";";
265 outputln(out);
266 output_tab(out, indent+1);
267 array_var->output_with_indices(out, ctrl_vars);
268 out << " = tmp;";
269 outputln(out);
270 }
271 else {
272 output_tab(out, indent+1);
273 array_var->output_with_indices(out, ctrl_vars);
274 out << " = ";
275 init_value->Output(out);
276 out << ";";
277 outputln(out);
278 }
279 output_tab(out, indent);
280 out << "}";
281 outputln(out);
282 }
283 // output the closing bracelets
284 for (i=1; i<array_var->get_dimension(); i++) {
285 indent--;
286 output_tab(out, indent);
287 out << "}";
288 outputln(out);
289 }
290 }
291
292 bool
visit_facts(vector<const Fact * > & inputs,CGContext & cg_context) const293 StatementArrayOp::visit_facts(vector<const Fact*>& inputs, CGContext& cg_context) const
294 {
295 // walk the iterations
296 size_t i;
297 for (i=0; i<array_var->get_dimension(); i++) {
298 const Variable *cv = ctrl_vars[i];
299 if (!cg_context.check_write_var(cv, inputs)) {
300 return false;
301 }
302 }
303 FactMgr* fm = get_fact_mgr(&cg_context);
304 // walk the body (if there is one)
305 if (body) {
306 FactVec facts_copy = inputs;
307 Effect eff = cg_context.get_effect_stm();
308 if (!body->visit_facts(inputs, cg_context)) {
309 return false;
310 }
311 // if body must return, means the control reached end of for-loop with pre-loop env
312 if (body->must_return()) {
313 inputs = facts_copy;
314 } else {
315 inputs = fm->map_facts_in[body];
316 }
317 // include the facts from "break" statements
318 // find edges leading to the end of this statement, and merge
319 vector<const CFGEdge*> edges;
320 find_edges_in(edges, true, false);
321 for (i=0; i<edges.size(); i++) {
322 const Statement* src = edges[i]->src;
323 FactMgr::merge_jump_facts(inputs, fm->map_facts_out[src]);
324 }
325 // compute accumulated effect
326 set_accumulated_effect_after_block(eff, body, cg_context);
327 }
328 // walk the initializing value, if this is an array initialization
329 else if (init_value) {
330 Lhs lhs(*array_var);
331 if (!init_value->visit_facts(inputs, cg_context)) {
332 return false;
333 }
334 if (!lhs.visit_facts(inputs, cg_context)) {
335 return false;
336 }
337 FactMgr::update_fact_for_assign(&lhs, init_value, inputs);
338 fm->map_stm_effect[this] = cg_context.get_effect_stm();
339 }
340 return true;
341 }
342
343 ///////////////////////////////////////////////////////////////////////////////
344
345 // Local Variables:
346 // c-basic-offset: 4
347 // tab-width: 4
348 // End:
349
350 // End of file.
351