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