1 // -*- mode: C++ -*-
2 //
3 // Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, 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 <cassert>
35 #include <iostream>
36 #include <sstream>
37 #include <vector>
38
39 #include "SafeOpFlags.h"
40 #include "random.h"
41 #include "Error.h"
42 #include "Probabilities.h"
43 #include "DepthSpec.h"
44 #include "MspFilters.h"
45 #include "CGOptions.h"
46
47 using namespace std;
48
49 vector<string> SafeOpFlags::wrapper_names;
50
SafeOpFlags()51 SafeOpFlags::SafeOpFlags()
52 {
53 //Nothing to do
54 }
55
SafeOpFlags(bool o1,bool o2,bool is_func,SafeOpSize osize)56 SafeOpFlags::SafeOpFlags(bool o1, bool o2, bool is_func, SafeOpSize osize)
57 : op1_(o1),
58 op2_(o2),
59 is_func_(is_func),
60 op_size_(osize)
61 {
62 //Nothing to do
63 }
64
SafeOpFlags(const SafeOpFlags & flags)65 SafeOpFlags::SafeOpFlags(const SafeOpFlags &flags)
66 : op1_(flags.op1_),
67 op2_(flags.op2_),
68 is_func_(flags.is_func_),
69 op_size_(flags.op_size_)
70 {
71
72 }
73
74 SafeOpFlags*
make_dummy_flags()75 SafeOpFlags::make_dummy_flags()
76 {
77 return new SafeOpFlags(false, false, false, sInt8);
78 }
79
80 eSimpleType
flags_to_type(bool sign,enum SafeOpSize size)81 SafeOpFlags::flags_to_type(bool sign, enum SafeOpSize size)
82 {
83 if (sign) {
84 switch(size) {
85 case sInt8: return eChar;
86 case sInt16: return eShort;
87 case sInt32: return eInt;
88 case sInt64: return eLongLong;
89 case sFloat: return eFloat;
90 default: assert(0); break;
91 }
92 }
93 else {
94 switch(size) {
95 case sInt8: return eUChar;
96 case sInt16: return eUShort;
97 case sInt32: return eUInt;
98 case sInt64: return eULongLong;
99 default: assert(0); break;
100 }
101 }
102 assert(0);
103 return eInt;
104 }
105
106 const Type*
get_lhs_type(void)107 SafeOpFlags::get_lhs_type(void)
108 {
109 eSimpleType st = flags_to_type(op1_, op_size_);
110 const Type& t = Type::get_simple_type(st);
111 return &t;
112 }
113
114 const Type*
get_rhs_type(void)115 SafeOpFlags::get_rhs_type(void)
116 {
117 eSimpleType st = flags_to_type(op2_, op_size_);
118 const Type& t = Type::get_simple_type(st);
119 return &t;
120 }
121
122 bool
return_float_type(const Type * rv_type,const Type * op1_type,const Type * op2_type,eBinaryOps bop)123 SafeOpFlags::return_float_type(const Type *rv_type, const Type *op1_type, const Type *op2_type,
124 eBinaryOps bop)
125 {
126 if (!CGOptions::enable_float())
127 return false;
128 if (rv_type && rv_type->is_float())
129 return true;
130 if ((op1_type && op1_type->is_float()) || (op2_type && op2_type->is_float()))
131 return true;
132 if (!FunctionInvocation::BinaryOpWorksForFloat(bop))
133 return false;
134 return false;
135 }
136
137 bool
return_float_type(const Type * rv_type,const Type * op1_type,eUnaryOps uop)138 SafeOpFlags::return_float_type(const Type *rv_type, const Type *op1_type, eUnaryOps uop)
139 {
140 if (!CGOptions::enable_float())
141 return false;
142 if (rv_type && rv_type->is_float())
143 return true;
144 if (op1_type && op1_type->is_float())
145 return true;
146 if (!FunctionInvocation::UnaryOpWorksForFloat(uop))
147 return false;
148 return false;
149 }
150
151
152 SafeOpFlags*
make_random_unary(const Type * rv_type,const Type * op1_type,eUnaryOps uop)153 SafeOpFlags::make_random_unary(const Type *rv_type, const Type *op1_type, eUnaryOps uop)
154 {
155 SafeOpFlags *flags = new SafeOpFlags();
156 assert("new SafeOpFlags fail!");
157 bool rv_is_float = return_float_type(rv_type, op1_type, uop);
158
159 // floating point is always signed
160 if (rv_is_float) {
161 assert(FunctionInvocation::UnaryOpWorksForFloat(uop) && "Invalid unary op");
162 flags->op1_ = true;
163 }
164 else {
165 flags->op1_ = rnd_flipcoin(SafeOpsSignedProb);
166 }
167 flags->op2_ = flags->op1_;
168
169 // ISSUE: in the old code, is_func is always true
170 // Probably need to be fixed later.
171 flags->is_func_ = true;
172
173 MspSafeOpSizeFilter *filter = new MspSafeOpSizeFilter(MAX_BINARY_OP);
174 Probabilities::register_extra_filter(pSafeOpsSizeProb, filter);
175 if (rv_is_float) {
176 assert(CGOptions::enable_float());
177 flags->op_size_ = sFloat;
178 }
179 else {
180 flags->op_size_ = (SafeOpSize)rnd_upto(MAX_SAFE_OP_SIZE-1, SAFE_OPS_SIZE_PROB_FILTER);
181 }
182 Probabilities::unregister_extra_filter(pSafeOpsSizeProb, filter);
183
184 delete filter;
185 return flags;
186 }
187
188 SafeOpFlags*
make_random_binary(const Type * rv_type,const Type * op1_type,const Type * op2_type,SafeOpKind op_kind,eBinaryOps bop)189 SafeOpFlags::make_random_binary(const Type *rv_type, const Type *op1_type, const Type *op2_type,
190 SafeOpKind op_kind, eBinaryOps bop)
191 {
192 DEPTH_GUARD_BY_TYPE_RETURN_WITH_FLAG(dtSafeOpFlags, op_kind, NULL);
193 SafeOpFlags *flags = new SafeOpFlags();
194 assert("new SafeOpFlags fail!");
195 bool rv_is_float = return_float_type(rv_type, op1_type, op2_type, bop);
196
197 // floating point is always signed
198 if (rv_is_float) {
199 if (op_kind == sOpBinary) {
200 assert(FunctionInvocation::BinaryOpWorksForFloat(bop) && "Invalid binary op");
201 }
202 flags->op1_ = true;
203 }
204 else {
205 flags->op1_ = rnd_flipcoin(SafeOpsSignedProb);
206 }
207 ERROR_GUARD_AND_DEL1(NULL, flags);
208
209 if (op_kind == sOpBinary) {
210 if (rv_is_float)
211 flags->op2_ = true;
212 else
213 flags->op2_ = rnd_flipcoin(SafeOpsSignedProb);
214 ERROR_GUARD_AND_DEL1(NULL, flags);
215 }
216 else {
217 flags->op2_ = flags->op1_;
218 }
219
220 // ISSUE: in the old code, is_func is always true
221 // Probably need to be fixed later.
222 flags->is_func_ = true;
223
224 MspSafeOpSizeFilter *filter = new MspSafeOpSizeFilter(bop);
225 Probabilities::register_extra_filter(pSafeOpsSizeProb, filter);
226
227 if (rv_is_float) {
228 assert(CGOptions::enable_float());
229 flags->op_size_ = sFloat;
230 }
231 else {
232 flags->op_size_ = (SafeOpSize)rnd_upto(MAX_SAFE_OP_SIZE-1, SAFE_OPS_SIZE_PROB_FILTER);
233 }
234 Probabilities::unregister_extra_filter(pSafeOpsSizeProb, filter);
235 ERROR_GUARD_AND_DEL2(NULL, flags, filter);
236
237 //Probabilities::unregister_extra_filter(pSafeOpsSizeProb, filter);
238 delete filter;
239 return flags;
240 }
241
242 SafeOpFlags *
clone() const243 SafeOpFlags::clone() const
244 {
245 return new SafeOpFlags(*this);
246 }
247
248 void
OutputSize(std::ostream & out) const249 SafeOpFlags::OutputSize(std::ostream &out) const
250 {
251 if(!op1_)
252 out << "u";
253
254 switch(op_size_) {
255 case sInt8:
256 out << "int8_t";
257 break;
258 case sInt16:
259 out << "int16_t";
260 break;
261 case sInt32:
262 out << "int32_t";
263 break;
264 case sInt64:
265 out << "int64_t";
266 break;
267 case sFloat:
268 out << "float";
269 break;
270 default:
271 assert(!"invalid size!");
272 break;
273 }
274 }
275
276 void
OutputFuncOrMacro(std::ostream & out) const277 SafeOpFlags::OutputFuncOrMacro(std::ostream &out) const
278 {
279 is_func_ ? (out << "func_")
280 : (out << "macro_");
281 }
282
283 void
OutputSign(std::ostream & out,bool is_signed) const284 SafeOpFlags::OutputSign(std::ostream &out, bool is_signed) const
285 {
286 is_signed ? (out << "_s")
287 : (out << "_u");
288 }
289
290 void
OutputOp1(std::ostream & out) const291 SafeOpFlags::OutputOp1(std::ostream &out) const
292 {
293 OutputSign(out, op1_);
294 }
295
296 void
OutputOp2(std::ostream & out) const297 SafeOpFlags::OutputOp2(std::ostream &out) const
298 {
299 OutputSign(out, op2_);
300 }
301
~SafeOpFlags()302 SafeOpFlags::~SafeOpFlags()
303 {
304 // Nothing to do
305 }
306
307 std::string
safe_float_func_string(enum eBinaryOps op) const308 SafeOpFlags::safe_float_func_string(enum eBinaryOps op) const
309 {
310 string s;
311 switch (op) {
312 case eAdd: s = "safe_add_"; break;
313 case eSub: s = "safe_sub_"; break;
314 case eMul: s = "safe_mul_"; break;
315 case eDiv: s = "safe_div_"; break;
316 default: assert(0); break;
317 }
318 s += "func_float_f_f";
319 return s;
320
321 }
322
323 /* find the safe math function/macro name */
324 std::string
to_string(enum eBinaryOps op) const325 SafeOpFlags::to_string(enum eBinaryOps op) const
326 {
327 if (op_size_ == sFloat)
328 return safe_float_func_string(op);
329 string s;
330 switch (op) {
331 case eAdd: s = "safe_add_"; break;
332 case eSub: s = "safe_sub_"; break;
333 case eMul: s = "safe_mul_"; break;
334 case eMod: s = "safe_mod_"; break;
335 case eDiv: s = "safe_div_"; break;
336 case eLShift: s = "safe_lshift_"; break;
337 case eRShift: s = "safe_rshift_"; break;
338 default: break;
339 }
340 ostringstream oss;
341 OutputFuncOrMacro(oss);
342 OutputSize(oss);
343 OutputOp1(oss);
344 (op == eLShift || op == eRShift) ? OutputOp2(oss) : OutputOp1(oss);
345 s += oss.str();
346 return s;
347 }
348
349 /* find the safe math function/macro name */
350 std::string
to_string(enum eUnaryOps op) const351 SafeOpFlags::to_string(enum eUnaryOps op) const
352 {
353 assert((op_size_ != sFloat) && "No safe unary function on floating point!");
354 string s;
355 switch (op) {
356 case eMinus: s = "safe_unary_minus_"; break;
357 default: break;
358 }
359 ostringstream oss;
360 OutputFuncOrMacro(oss);
361 OutputSize(oss);
362 OutputOp1(oss);
363 s += oss.str();
364 return s;
365 }
366
367 /* assign id to safe math function */
368 int
to_id(std::string fname)369 SafeOpFlags::to_id(std::string fname)
370 {
371 for (size_t i=0; i<wrapper_names.size(); i++) {
372 if (wrapper_names[i] == fname) {
373 return i+1;
374 }
375 }
376 wrapper_names.push_back(fname);
377 return wrapper_names.size();
378 }
379