1 // -*- mode: C++ -*-
2 //
3 // Copyright (c) 2007, 2008, 2009, 2010, 2011, 2014, 2015, 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 "FunctionInvocationBinary.h"
35 #include <cassert>
36 
37 #include "Common.h"
38 
39 #include "CGOptions.h"
40 #include "Expression.h"
41 #include "FactMgr.h"
42 #include "Type.h"
43 #include "SafeOpFlags.h"
44 #include "CGContext.h"
45 #include "Block.h"
46 #include "random.h"
47 
48 using namespace std;
49 
50 static vector<bool> needcomma;  // Flag to track output of commas
51 
52 ///////////////////////////////////////////////////////////////////////////////
53 
54 FunctionInvocationBinary *
CreateFunctionInvocationBinary(CGContext & cg_context,eBinaryOps op,SafeOpFlags * flags)55 FunctionInvocationBinary::CreateFunctionInvocationBinary(CGContext &cg_context,
56 						eBinaryOps op,
57 						SafeOpFlags *flags)
58 {
59 	FunctionInvocationBinary *fi = NULL;
60 	assert(flags);
61 
62 	if (flags && FunctionInvocationBinary::safe_ops(op)) {
63 		bool op1 = flags->get_op1_sign();
64 		bool op2 = flags->get_op2_sign();
65 		enum SafeOpSize size = flags->get_op_size();
66 
67 		eSimpleType type1 = SafeOpFlags::flags_to_type(op1, size);
68 		eSimpleType type2 = SafeOpFlags::flags_to_type(op2, size);
69 
70 		const Block *blk = cg_context.get_current_block();
71 		assert(blk);
72 
73 		std::string tmp_var1 = blk->create_new_tmp_var(type1);
74 		std::string tmp_var2;
75 		if (op == eLShift || op == eRShift)
76 			tmp_var2 = blk->create_new_tmp_var(type2);
77 		else
78 			tmp_var2 = blk->create_new_tmp_var(type1);
79 
80 		fi = new FunctionInvocationBinary(op, flags, tmp_var1, tmp_var2);
81 	}
82 	else {
83 		fi = new FunctionInvocationBinary(op, flags);
84 	}
85 	return fi;
86 }
87 
88 
89 /*
90  * XXX: replace with a useful constructor.
91  */
FunctionInvocationBinary(eBinaryOps op,const SafeOpFlags * flags)92 FunctionInvocationBinary::FunctionInvocationBinary(eBinaryOps op, const SafeOpFlags *flags)
93 	: FunctionInvocation(eBinaryPrim, flags),
94 	  eFunc(op),
95 	  tmp_var1(""),
96 	  tmp_var2("")
97 {
98 	// Nothing else to do.  Caller must build useful params.
99 }
100 
FunctionInvocationBinary(eBinaryOps op,const SafeOpFlags * flags,std::string & name1,std::string & name2)101 FunctionInvocationBinary::FunctionInvocationBinary(eBinaryOps op, const SafeOpFlags *flags,
102 						std::string &name1, std::string &name2)
103 	: FunctionInvocation(eBinaryPrim, flags),
104 	  eFunc(op),
105 	  tmp_var1(name1),
106 	  tmp_var2(name2)
107 {
108 	// Nothing else to do.  Caller must build useful params.
109 }
110 
111 /*
112  * copy constructor
113  */
FunctionInvocationBinary(const FunctionInvocationBinary & fbinary)114 FunctionInvocationBinary::FunctionInvocationBinary(const FunctionInvocationBinary &fbinary)
115 	: FunctionInvocation(fbinary),
116 	  eFunc(fbinary.eFunc),
117 	  tmp_var1(fbinary.tmp_var1),
118 	  tmp_var2(fbinary.tmp_var2)
119 {
120 	// Nothing to do
121 }
122 
FunctionInvocationBinary(eBinaryOps op,const Expression * exp1,const Expression * exp2,const SafeOpFlags * flags)123 FunctionInvocationBinary::FunctionInvocationBinary(eBinaryOps op , const Expression* exp1, const Expression* exp2, const SafeOpFlags *flags)
124 	: FunctionInvocation(eBinaryPrim, flags),
125 	  eFunc(op)
126 {
127 	param_value.clear();
128 	add_operand(exp1);
129 	add_operand(exp2);
130 }
131 
132 /*
133  *
134  */
~FunctionInvocationBinary(void)135 FunctionInvocationBinary::~FunctionInvocationBinary(void)
136 {
137 	// Nothing to do.
138 }
139 
140 /*
141  *
142  */
143 FunctionInvocation *
clone() const144 FunctionInvocationBinary::clone() const
145 {
146 	return new FunctionInvocationBinary(*this);
147 }
148 ///////////////////////////////////////////////////////////////////////////////
149 
150 bool
safe_ops(eBinaryOps op)151 FunctionInvocationBinary::safe_ops(eBinaryOps op)
152 {
153 	switch(op) {
154 	case eAdd:
155 	case eSub:
156 	case eMul:
157 	case eMod:
158 	case eDiv:
159 	case eLShift:
160 	case eRShift:
161 		return true;
162 	default:
163 		return false;
164 	}
165 }
166 
167 /* do some constant folding */
168 bool
equals(int num) const169 FunctionInvocationBinary::equals(int num) const
170 {
171 	assert(param_value.size() == 2);
172 	if (num == 0) {
173 		if (param_value[0]->equals(0) &&
174 			(eFunc==eMul || eFunc==eDiv || eFunc==eMod || eFunc==eLShift || eFunc==eRShift || eFunc==eAnd || eFunc==eBitAnd)) {
175 			return true;
176 		}
177 		if (param_value[1]->equals(0) && (eFunc==eMul || eFunc==eAnd || eFunc==eBitAnd)) {
178 			return true;
179 		}
180 		if (param_value[0] == param_value[1] && (eFunc==eSub || eFunc==eCmpGt || eFunc==eCmpLt || eFunc==eCmpNe)) {
181 			return true;
182 		}
183 		if ((param_value[1]->equals(1) || param_value[1]->equals(-1)) && eFunc==eMod) {
184 			return true;
185 		}
186 	}
187 	return false;
188 }
189 
190 bool
is_0_or_1(void) const191 FunctionInvocationBinary::is_0_or_1(void) const
192 {
193 	return eFunc==eCmpGt || eFunc==eCmpLt || eFunc==eCmpGe || eFunc==eCmpLe || eFunc==eCmpEq || eFunc==eCmpNe;
194 }
195 
196 bool
is_return_type_float() const197 FunctionInvocationBinary::is_return_type_float() const
198 {
199 	assert(op_flags);
200 	return op_flags->get_op_size() == sFloat;
201 }
202 
203 /*
204  * XXX --- we should memoize the types of "standard functions."
205  */
206 const Type &
get_type(void) const207 FunctionInvocationBinary::get_type(void) const
208 {
209 	if (is_return_type_float())
210 		return Type::get_simple_type(eFloat);
211 	switch (eFunc) {
212 	default:
213 		assert(!"invalid operator in FunctionInvocationBinary::get_type()");
214 		break;
215 
216 	case eAdd:
217 	case eSub:
218 	case eMul:
219 	case eDiv:
220 	case eMod:
221 	case eBitXor:
222 	case eBitAnd:
223 	case eBitOr:
224 		{
225 			const Type &l_type = param_value[0]->get_type();
226 			const Type &r_type = param_value[1]->get_type();
227 			// XXX --- not really right!
228 			if ((l_type.is_signed()) && (r_type.is_signed())) {
229 				return Type::get_simple_type(eInt);
230 			} else {
231 				return Type::get_simple_type(eUInt);
232 			}
233 		}
234 		break;
235 
236 	case eCmpGt:
237 	case eCmpLt:
238 	case eCmpGe:
239 	case eCmpLe:
240 	case eCmpEq:
241 	case eCmpNe:
242 	case eAnd:
243 	case eOr:
244 		return Type::get_simple_type(eInt);
245 		break;
246 
247 	case eRShift:
248 	case eLShift:
249 		{
250 			const Type &l_type = param_value[0]->get_type();
251 			// XXX --- not really right!
252 			if (l_type.is_signed()) {
253 				return Type::get_simple_type(eInt);
254 			} else {
255 				return Type::get_simple_type(eUInt);
256 			}
257 		}
258 		break;
259 	}
260 	assert(0);
261 	return Type::get_simple_type(eInt);
262 }
263 
264 ///////////////////////////////////////////////////////////////////////////////
265 
266 /*
267  *
268  */
269 static void
OutputStandardFuncName(eBinaryOps eFunc,std::ostream & out)270 OutputStandardFuncName(eBinaryOps eFunc, std::ostream &out)
271 {
272 	switch (eFunc) {
273 		// Math Ops
274 	case eAdd:		out << "+";     break;
275 	case eSub:		out << "-";     break;
276 	case eMul:		out << "*";     break;
277 	case eDiv:		out << "/";     break;
278 	case eMod:		out << "%";     break;
279 
280 		// Logical Ops
281 	case eAnd:		out << "&&";	break;
282 	case eOr:		out << "||";	break;
283 	case eCmpEq:	out << "==";	break;
284 	case eCmpNe:	out << "!=";	break;
285 	case eCmpGt:	out << ">";		break;
286 	case eCmpLt:	out << "<";		break;
287 	case eCmpLe:	out << "<=";	break;
288 	case eCmpGe:	out << ">=";	break;
289 
290 		// Bitwise Ops
291 	case eBitAnd:	out << "&";		break;
292 	case eBitOr:	out << "|";		break;
293 	case eBitXor:	out << "^";		break;
294 	case eLShift:	out << "<<";    break;
295 	case eRShift:	out << ">>";    break;
296 	}
297 }
298 
299 std::string
get_binop_string(eBinaryOps bop)300 FunctionInvocationBinary::get_binop_string(eBinaryOps bop)
301 {
302 	string op_string;
303 	switch (bop)
304 	{
305 	case eAdd: op_string = "+"; break;
306 	case eSub: op_string = "-"; break;
307 	case eMul: op_string = "*"; break;
308 	case eDiv: op_string = "/"; break;
309 	case eMod: op_string = "%"; break;
310 	case eBitAnd:	op_string = "&"; break;
311 	case eBitXor:	op_string = "^"; break;
312 	case eBitOr:  op_string = "|"; break;
313 	default: assert(0); break;
314 	}
315 	return op_string;
316 }
317 
318 /*
319  *
320  */
321 void
Output(std::ostream & out) const322 FunctionInvocationBinary::Output(std::ostream &out) const
323 {
324 	bool need_cast = false;
325 	out << "(";
326 	// special case for mutated array subscripts, see ArrayVariable::rnd_mutate
327 	// the rational is we don't need overflow check for this addition because
328 	// the induction variable is small --- less than the size of array, which
329 	// has a small upper bound
330 	if (eFunc == eAdd && op_flags == 0) {
331 		param_value[0]->Output(out);
332 		out << " + ";
333 		param_value[1]->Output(out);
334 	}
335 	else {
336 		switch (eFunc) {
337 		case eAdd:
338 		case eSub:
339 		case eMul:
340 		case eMod:
341 		case eDiv:
342 		case eLShift:
343 		case eRShift:
344 			if (CGOptions::avoid_signed_overflow()) {
345 				string fname = op_flags->to_string(eFunc);
346 				int id = SafeOpFlags::to_id(fname);
347 				// don't use safe math wrapper if this function is specified in "--safe-math-wrapper"
348 				if (CGOptions::safe_math_wrapper(id)) {
349 					out << fname << "(";
350 					if (CGOptions::math_notmp()) {
351 						out << tmp_var1 << ", ";
352 					}
353 					param_value[0]->Output(out);
354 					out << ", ";
355 
356 					if (CGOptions::math_notmp()) {
357 						out << tmp_var2 << ", ";
358 					}
359 					param_value[1]->Output(out);
360 					if (CGOptions::identify_wrappers()) {
361 						out << ", " << id;
362 					}
363 					out << ")";
364 					break;
365 				}
366 			}
367 			need_cast = true;
368 			// fallthrough!
369 
370 		default:
371 			// explicit type casting for op1
372 			if (need_cast) {
373 				out << "(";
374 				op_flags->OutputSize(out);
375 				out << ")";
376 			}
377 			param_value[0]->Output(out);
378 			out << " ";
379 			OutputStandardFuncName(eFunc, out);
380 			out << " ";
381 			// explicit type casting for op2
382 			if (need_cast) {
383 				out << "(";
384 				op_flags->OutputSize(out);
385 				out << ")";
386 			}
387 			param_value[1]->Output(out);
388 			break;
389 		}
390 	}
391 	out << ")";
392 }
393 
394 /*
395  *
396  */
397 void
indented_output(std::ostream & out,int indent) const398 FunctionInvocationBinary::indented_output(std::ostream &out, int indent) const
399 {
400 	if (has_simple_params()) {
401 		output_tab(out, indent);
402 		Output(out);
403 		return;
404 	}
405 	output_open_encloser("(", out, indent);
406 	// special case for mutated array subscripts, see ArrayVariable::rnd_mutate
407 	// the rational is we don't need overflow check for this addition because
408 	// the induction variable is small --- less than the size of array, which
409 	// by default is 10 at most
410 	if (eFunc == eAdd && op_flags == 0) {
411 		param_value[0]->indented_output(out, indent);
412 		out << " + ";
413 		outputln(out);
414 		param_value[1]->indented_output(out, indent);
415 	}
416 	else {
417 		switch (eFunc) {
418 		case eAdd:
419 		case eSub:
420 		case eMul:
421 		case eMod:
422 		case eDiv:
423 		case eLShift:
424 		case eRShift:
425 			if (CGOptions::avoid_signed_overflow()) {
426 				output_tab(out, indent);
427 				out << op_flags->to_string(eFunc);
428 				outputln(out);
429 				output_open_encloser("(", out, indent);
430 				if (CGOptions::math_notmp()) {
431 					output_tab(out, indent);
432 					out << tmp_var1 << ", ";
433 				}
434 				outputln(out);
435 				param_value[0]->indented_output(out, indent);
436 				out << ", ";
437 				outputln(out);
438 				if (CGOptions::math_notmp()) {
439 					output_tab(out, indent);
440 					out << tmp_var2 << ", ";
441 				}
442 				outputln(out);
443 				param_value[1]->indented_output(out, indent);
444 				output_close_encloser(")", out, indent);
445 				break;
446 			}
447 			// fallthrough!
448 
449 		default:
450 			param_value[0]->indented_output(out, indent);
451 			out << " ";
452 			OutputStandardFuncName(eFunc, out);
453 			out << " ";
454 			outputln(out);
455 			param_value[1]->indented_output(out, indent);
456 			break;
457 		}
458 	}
459 	output_close_encloser(")", out, indent);
460 }
461 
462 bool
visit_facts(vector<const Fact * > & inputs,CGContext & cg_context) const463 FunctionInvocationBinary::visit_facts(vector<const Fact*>& inputs, CGContext& cg_context) const
464 {
465 	bool skippable = IsOrderedStandardFunc(eFunc);
466 	assert(param_value.size() == 2);
467 	if (skippable) {
468 		const Expression* value = param_value[0];
469 		if (value->visit_facts(inputs, cg_context)) {
470 			vector<const Fact*> inputs_copy = inputs;
471 			value = param_value[1];
472 			if (value->visit_facts(inputs, cg_context)) {
473 				// the second parameter may or may not be evaludated, thus need to
474 				// merge with the post-param0 env.
475 				merge_facts(inputs, inputs_copy);
476 				return true;
477 			}
478 		}
479 		return false;
480 	}
481 	// for other binary invocations, use the standard visitor
482 	return FunctionInvocation::visit_facts(inputs, cg_context);
483 }
484 
485 ///////////////////////////////////////////////////////////////////////////////
486 
487 // Local Variables:
488 // c-basic-offset: 4
489 // tab-width: 4
490 // End:
491 
492 // End of file.
493