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