1 // -*- mode: C++ -*-
2 //
3 // Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, 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 <cassert>
35 #include <iostream>
36 #include "CVQualifiers.h"
37 #include "Type.h"
38 #include "Effect.h"
39 #include "CGContext.h"
40 #include "CGOptions.h"
41 #include "random.h"
42 #include "Error.h"
43 #include "Probabilities.h"
44 #include "DepthSpec.h"
45 #include "Enumerator.h"
46 
47 //////////////////////////////////////////////////////////////////////
48 // Construction/Destruction
49 //////////////////////////////////////////////////////////////////////
CVQualifiers(void)50 CVQualifiers::CVQualifiers(void)
51 : wildcard(false),
52   accept_stricter(false)
53 {
54 	// nothing else to do
55 }
56 
CVQualifiers(bool wild,bool accept_stricter)57 CVQualifiers::CVQualifiers(bool wild, bool accept_stricter)
58 : wildcard(wild),
59   accept_stricter(accept_stricter)
60 {
61 	// nothing else to do
62 }
63 
CVQualifiers(const vector<bool> & isConsts,const vector<bool> & isVolatiles)64 CVQualifiers::CVQualifiers(const vector<bool>& isConsts, const vector<bool>& isVolatiles)
65 : wildcard(false),
66   accept_stricter(false),
67   is_consts(isConsts),
68   is_volatiles(isVolatiles)
69 {
70 	// nothing else to do
71 }
72 
CVQualifiers(const CVQualifiers & qfer)73 CVQualifiers::CVQualifiers(const CVQualifiers &qfer)
74 : wildcard(qfer.wildcard),
75   accept_stricter(qfer.accept_stricter),
76   is_consts(qfer.get_consts()),
77   is_volatiles(qfer.get_volatiles())
78 {
79 	// nothing else to do
80 }
81 
~CVQualifiers()82 CVQualifiers::~CVQualifiers()
83 {
84 }
85 
86 CVQualifiers &
operator =(const CVQualifiers & qfer)87 CVQualifiers::operator=(const CVQualifiers &qfer)
88 {
89 	if (this == &qfer) {
90 		return *this;
91 	}
92 	wildcard = qfer.wildcard;
93 	accept_stricter = qfer.accept_stricter;
94 	is_consts = qfer.get_consts();
95 	is_volatiles = qfer.get_volatiles();
96 	return *this;
97 }
98 
99 // --------------------------------------------------------------
100  /* return true if this variable is more const-volatile qualified than v
101   * some examples are:
102   *    const is more qualified than none
103   *    volatile is more qualified than none
104   *    const volatile is more qualified than const
105   *    const is NOT more qualified than volatile
106   *    ...
107   *  notice "const int**" is not convertable from "int**"
108   *  as explained in
109   * http://www.embedded.com/columns/programmingpointers/180205632?_requestid=488055
110   **************************************************************/
111 bool
stricter_than(const CVQualifiers & qfer) const112 CVQualifiers::stricter_than(const CVQualifiers& qfer) const
113 {
114 	size_t i;
115 	assert(is_consts.size() == is_volatiles.size());
116 	const vector<bool>& v_consts = qfer.get_consts();
117 	const vector<bool>& v_volatiles = qfer.get_volatiles();
118 	if (is_consts.size() != v_consts.size() || is_volatiles.size() != v_volatiles.size()) {
119 		return false;
120 	}
121 
122 	size_t depth = is_consts.size();
123 	// check "const" qualifier first
124 	for (i=0; i<depth; i++) {
125 		// for special rule: "const int**" is not convertable from "int**"
126 		// actually for a level that is followed by two "*"s, we have to match
127 		// "const" qualifier
128 		if (depth - i > 2 && is_consts[i] != v_consts[i]) {
129 			return false;
130 		}
131 		if (v_consts[i] && !is_consts[i]) {
132 			return false;
133 		}
134 	}
135 
136 	// check "volatile" qualifier second
137 	// special rule: the volatile property on storage (1st in vector) must match
138 	// can be relaxed???
139 	if (depth > 1 && is_volatiles[0] != v_volatiles[0]) {
140 		return false;
141 	}
142 	for (i=0; i<depth; i++) {
143 		// similiar to const: "volatile int**" is not convertable from "int**"
144 		// actually for a level that is followed by two "*"s, we have to match
145 		if (depth - i > 2 && is_volatiles[i] != v_volatiles[i]) {
146 			return false;
147 		}
148 		if (v_volatiles[i] && !is_volatiles[i]) {
149 			return false;
150 		}
151 	}
152 	return true;
153 }
154 
155 bool
match(const CVQualifiers & qfer) const156 CVQualifiers::match(const CVQualifiers& qfer) const
157 {
158 	if (wildcard) {
159 		return true;
160 	}
161 	if (CGOptions::match_exact_qualifiers()) {
162 		return is_consts == qfer.get_consts() && is_volatiles == qfer.get_volatiles();
163 	}
164 	// return true if both variables are non-pointer (has only one level qualifier)
165 	if (is_consts.size() == qfer.get_consts().size() && is_consts.size()==1) {
166 		assert(is_consts.size() == is_volatiles.size());
167 		return true;
168 	}
169 	return (!accept_stricter && stricter_than(qfer)) || (accept_stricter && qfer.stricter_than(*this));
170 }
171 
172 bool
match_indirect(const CVQualifiers & qfer) const173 CVQualifiers::match_indirect(const CVQualifiers& qfer) const
174 {
175 	if (wildcard) {
176 		return true;
177 	}
178 	if (is_consts.size() == qfer.get_consts().size()) {
179 		return match(qfer);
180 	}
181 	int deref = qfer.get_consts().size() - is_consts.size();
182 	if (deref < -1) {
183 		return false;
184 	}
185 	return match(qfer.indirect_qualifiers(deref));
186 }
187 
188 /*
189  * make sure no volatile-pointers if volatile-pointers is false
190  */
191 void
make_scalar_volatiles(std::vector<bool> & volatiles)192 CVQualifiers::make_scalar_volatiles(std::vector<bool> &volatiles)
193 {
194 	if (!CGOptions::volatile_pointers() || !CGOptions::global_variables()) {
195 		for (size_t i=1; i<volatiles.size(); i++)
196 			volatiles[i] = false;
197 	}
198 }
199 
200 /*
201  * make sure no const-pointers if const_pointers is false
202  */
203 void
make_scalar_consts(std::vector<bool> & consts)204 CVQualifiers::make_scalar_consts(std::vector<bool> &consts)
205 {
206 	if (!CGOptions::const_pointers()) {
207 		for (size_t i=1; i<consts.size(); i++)
208 			consts[i] = false;
209 	}
210 }
211 
212 /*
213  * generate a random CV qualifier vector that is looser or stricter than this one
214  */
215 CVQualifiers
random_qualifiers(bool no_volatile,Effect::Access access,const CGContext & cg_context) const216 CVQualifiers::random_qualifiers(bool no_volatile, Effect::Access access, const CGContext &cg_context) const
217 {
218 	std::vector<bool> volatiles;
219 	std::vector<bool> consts;
220 	if (wildcard) {
221 		return CVQualifiers(true, accept_stricter);
222 	}
223 	// use non-volatile for all levels if requested
224 	if (no_volatile) {
225 		for (size_t i=0; i<is_volatiles.size(); i++) {
226 			volatiles.push_back(false);
227 		}
228 	}
229 	else {
230 		volatiles = !accept_stricter ? random_looser_volatiles() : random_stricter_volatiles();
231 		ERROR_GUARD(CVQualifiers(consts, volatiles));
232 		if (!cg_context.get_effect_context().is_side_effect_free()) {
233 			volatiles[volatiles.size() - 1] = false;
234 		}
235 	}
236 
237 	ERROR_GUARD(CVQualifiers(consts, volatiles));
238 	make_scalar_volatiles(volatiles);
239 	consts = !accept_stricter ? random_looser_consts() : random_stricter_consts();
240 	make_scalar_consts(consts);
241 	ERROR_GUARD(CVQualifiers(consts, volatiles));
242 	if (access == Effect::WRITE) {
243 		consts[consts.size() - 1] = false;
244 	}
245 	return CVQualifiers(consts, volatiles);
246 }
247 
248 /*
249  * generate a random CV qualifier vector that is looser than this one
250  */
251 CVQualifiers
random_loose_qualifiers(bool no_volatile,Effect::Access access,const CGContext & cg_context) const252 CVQualifiers::random_loose_qualifiers(bool no_volatile, Effect::Access access, const CGContext &cg_context) const
253 {
254 	std::vector<bool> volatiles;
255 	std::vector<bool> consts;
256 	if (wildcard) {
257 		return CVQualifiers(true, accept_stricter);
258 	}
259 	// use non-volatile for all levels if requested
260 	if (no_volatile) {
261 		for (size_t i=0; i<is_volatiles.size(); i++) {
262 			volatiles.push_back(false);
263 		}
264 	}
265 	else {
266 		volatiles = random_looser_volatiles();
267 		ERROR_GUARD(CVQualifiers(consts, volatiles));
268 		if (!cg_context.get_effect_context().is_side_effect_free()) {
269 			volatiles[volatiles.size() - 1] = false;
270 		}
271 	}
272 	ERROR_GUARD(CVQualifiers(consts, volatiles));
273 	make_scalar_volatiles(volatiles);
274 
275 	consts = random_looser_consts();
276 	make_scalar_consts(consts);
277 	ERROR_GUARD(CVQualifiers(consts, volatiles));
278 	if (access == Effect::WRITE) {
279 		consts[consts.size() - 1] = false;
280 	}
281 	return CVQualifiers(consts, volatiles);
282 }
283 
284 CVQualifiers
random_qualifiers(const Type * t,Effect::Access access,const CGContext & cg_context,bool no_volatile)285 CVQualifiers::random_qualifiers(const Type* t, Effect::Access access,
286 				const CGContext &cg_context, bool no_volatile)
287 {
288 	return random_qualifiers(t, access, cg_context, no_volatile, RegularConstProb, RegularVolatileProb);
289 }
290 
is_volatile_ok_on_one_level(const Type * t)291 static bool is_volatile_ok_on_one_level(const Type* t)
292 {
293 	if (!CGOptions::lang_cpp()) return true;
294 	if (t->eType != eStruct && t->eType != eUnion) return true;
295 
296 	if (!t->has_assign_ops()) return false;
297 	if (t->eType == eStruct) return true;
298 
299 	// Union with a struct field: we can't make it volatile, or we won't be able to assign to/from that field
300 	for (size_t i = 0; i < t->fields.size(); ++i) {
301 		const Type* field = t->fields[i];
302 
303 		if (field->eType == eStruct)
304 			return false;
305 		if (field->eType == eUnion){
306 			if (!is_volatile_ok_on_one_level(field))
307 				return false;
308 		}
309 	}
310 	return true;
311 }
312 
313 CVQualifiers
random_qualifiers(const Type * t,Effect::Access access,const CGContext & cg_context,bool no_volatile,unsigned int const_prob,unsigned int volatile_prob)314 CVQualifiers::random_qualifiers(const Type* t, Effect::Access access, const CGContext &cg_context, bool no_volatile,
315 					unsigned int const_prob, unsigned int volatile_prob)
316 {
317 	CVQualifiers ret_qfer;
318 	if (t==0) {
319 		return ret_qfer;
320 	}
321 	bool isVolatile = false;
322 	bool isConst = false;
323 	std::vector<bool> is_consts, is_volatiles;
324 	const Effect &effect_context = cg_context.get_effect_context();
325 
326 	// set random volatile/const properties for each level of indirection for pointers
327 	// First set up the vectors with correct number of qualifiers:
328 	unsigned level = 0;
329 	const Type* tmp = t->ptr_type;
330 	while (tmp) {
331 		++level;
332 		is_consts.push_back(false);
333 		is_volatiles.push_back(false);
334 		tmp = tmp->ptr_type;
335 	}
336 	// Then make the random properties (properties need to be in reverse order):
337 	tmp = t->ptr_type;
338 	while (tmp) {
339 		bool volatile_ok = is_volatile_ok_on_one_level(tmp);
340 		isVolatile = volatile_ok? rnd_flipcoin(volatile_prob): false;
341 		isConst = rnd_flipcoin(const_prob);
342 		if (isVolatile && isConst && !CGOptions::allow_const_volatile()) {
343 			isConst = false;
344 		}
345 		assert(level > 0);
346 		is_consts[level-1] = isConst;
347 		is_volatiles[level-1] = isVolatile;
348 		--level;
349 		tmp = tmp->ptr_type;
350 	}
351 
352 	// set random volatile/const properties for variable itself
353 	bool volatile_ok = effect_context.is_side_effect_free() && is_volatile_ok_on_one_level(t);
354 	bool const_ok = (access != Effect::WRITE);
355 
356 	isVolatile = volatile_ok ? rnd_flipcoin(volatile_prob) : false;
357 	isConst = const_ok ? rnd_flipcoin(const_prob) : false;
358 	if (isVolatile && isConst && !CGOptions::allow_const_volatile()) {
359 		isConst = false;
360 	}
361 	is_consts.push_back(isConst);
362 	is_volatiles.push_back(isVolatile);
363 	// use non-volatile for all levels if requested
364 	if (no_volatile) {
365 		for (size_t i=0; i<is_volatiles.size(); i++) {
366 			is_volatiles[i] = false;
367 		}
368 	}
369 	make_scalar_volatiles(is_volatiles);
370 	make_scalar_consts(is_consts);
371 	return CVQualifiers(is_consts, is_volatiles);
372 }
373 
374 /*
375  * make a random qualifier for type t, assuming non context,
376  * and no volatile allowed
377  */
378 CVQualifiers
random_qualifiers(const Type * t)379 CVQualifiers::random_qualifiers(const Type* t)
380 {
381 	return random_qualifiers(t, Effect::READ, CGContext::get_empty_context(), true);
382 }
383 
384 /*
385  * be careful to use it because it will generate volatile without knowing the context.
386  * Only used to generate qulifiers for struct/unions
387  */
388 CVQualifiers
random_qualifiers(const Type * t,unsigned int const_prob,unsigned int volatile_prob)389 CVQualifiers::random_qualifiers(const Type* t, unsigned int const_prob, unsigned int volatile_prob)
390 {
391 	return random_qualifiers(t, Effect::READ, CGContext::get_empty_context(), false, const_prob, volatile_prob);
392 }
393 
394 vector<bool>
random_stricter_consts(void) const395 CVQualifiers::random_stricter_consts(void) const
396 {
397 	vector<bool> consts;
398 	size_t i;
399 	size_t depth = is_consts.size();
400 	if (CGOptions::match_exact_qualifiers()) return is_consts;
401 	for (i=0; i<depth; i++) {
402 		// special case
403 		// const int** is not stricter than int**
404 		// int * const ** is not stricter than int***
405 		// and so on...
406 		if (is_consts[i] || (depth - i > 2)) {
407 			consts.push_back(is_consts[i]);
408 		}
409 		else if (is_volatiles[i] && !CGOptions::allow_const_volatile()) {
410 			consts.push_back(false);
411 		}
412 		else {
413 			DEPTH_GUARD_BY_DEPTH_RETURN(1, consts);
414 			bool index = rnd_flipcoin(StricterConstProb);
415 			ERROR_GUARD(consts);
416 			consts.push_back(index);
417 		}
418 	}
419 	return consts;
420 }
421 
422 vector<bool>
random_stricter_volatiles(void) const423 CVQualifiers::random_stricter_volatiles(void) const
424 {
425 	vector<bool> volatiles;
426 	size_t i;
427 	size_t depth = is_volatiles.size();
428 	if (CGOptions::match_exact_qualifiers()) return is_volatiles;
429 	for (i=0; i<depth; i++) {
430 		// first one (storage must match, any level followed by at least two more
431 		// indirections must match
432 		if (is_volatiles[i] || (i==0 && depth>1) || (depth - i > 2)) {
433 			volatiles.push_back(is_volatiles[i]);
434 		}
435 		else if (is_consts[i] && !CGOptions::allow_const_volatile()) {
436 			volatiles.push_back(false);
437 		}
438 		else {
439 			DEPTH_GUARD_BY_DEPTH_RETURN(1, volatiles);
440 			bool index = rnd_flipcoin(RegularVolatileProb);
441 			ERROR_GUARD(volatiles);
442 			volatiles.push_back(index);
443 		}
444 	}
445 	make_scalar_volatiles(volatiles);
446 	return volatiles;
447 }
448 
449 vector<bool>
random_looser_consts(void) const450 CVQualifiers::random_looser_consts(void) const
451 {
452 	vector<bool> consts;
453 	size_t i;
454 	size_t depth = is_consts.size();
455 	if (CGOptions::match_exact_qualifiers()) return is_consts;
456 	for (i=0; i<depth; i++) {
457 		// special case
458 		if (!is_consts[i] || (depth - i > 2)) {
459 			consts.push_back(is_consts[i]);
460 		}
461 		else {
462 			DEPTH_GUARD_BY_DEPTH_RETURN(1, consts);
463 			bool index = rnd_flipcoin(LooserConstProb);
464 			ERROR_GUARD(consts);
465 			consts.push_back(index);
466 		}
467 	}
468 	return consts;
469 }
470 
471 vector<bool>
random_looser_volatiles(void) const472 CVQualifiers::random_looser_volatiles(void) const
473 {
474 	vector<bool> volatiles;
475 	size_t i;
476 	size_t depth = is_volatiles.size();
477 	if (CGOptions::match_exact_qualifiers()) return is_volatiles;
478 	for (i=0; i<depth; i++) {
479 		if (!is_volatiles[i] || (i==0 && depth>1) || (depth - i > 2)) {
480 			volatiles.push_back(is_volatiles[i]);
481 		}
482 		else {
483 			DEPTH_GUARD_BY_DEPTH_RETURN(1, volatiles);
484 			bool index = rnd_flipcoin(RegularVolatileProb);
485 			ERROR_GUARD(volatiles);
486 			volatiles.push_back(index);
487 		}
488 	}
489 	make_scalar_volatiles(volatiles);
490 	return volatiles;
491 }
492 
493 void
add_qualifiers(bool is_const,bool is_volatile)494 CVQualifiers::add_qualifiers(bool is_const, bool is_volatile)
495 {
496 	is_consts.push_back(is_const);
497 	is_volatiles.push_back(is_volatile);
498 }
499 
500 
501 // actually add qualifiers to pointers
502 CVQualifiers
random_add_qualifiers(bool no_volatile) const503 CVQualifiers::random_add_qualifiers(bool no_volatile) const
504 {
505 	CVQualifiers qfer = *this;
506 	if (CGOptions::match_exact_qualifiers()) {
507 		qfer.add_qualifiers(false, false);
508 		return qfer;
509 	}
510 	//bool is_const = rnd_upto(50);
511 	if (no_volatile) {
512 		DEPTH_GUARD_BY_DEPTH_RETURN(1, qfer);
513 	}
514 	else {
515 		DEPTH_GUARD_BY_DEPTH_RETURN(2, qfer);
516 	}
517 
518 	bool is_const;
519 	if (!CGOptions::const_pointers())
520 		is_const = false;
521 	else
522 		is_const = rnd_flipcoin(RegularConstProb);
523 	ERROR_GUARD(qfer);
524 	//bool is_volatile = no_volatile ? false : rnd_upto(RegularVolatileProb);
525 	bool is_volatile;
526 	if (no_volatile || !CGOptions::volatile_pointers())
527 		is_volatile = false;
528 	else
529 		is_volatile = rnd_flipcoin(RegularVolatileProb);
530 
531 	ERROR_GUARD(qfer);
532 	qfer.add_qualifiers(is_const, is_volatile);
533 	return qfer;
534 }
535 
536 void
remove_qualifiers(int len)537 CVQualifiers::remove_qualifiers(int len)
538 {
539 	int i;
540 	for (i=0; i<len; i++) {
541 		is_consts.pop_back();
542 		is_volatiles.pop_back();
543 	}
544 }
545 
546 CVQualifiers
indirect_qualifiers(int level) const547 CVQualifiers::indirect_qualifiers(int level) const
548 {
549 	if (level == 0 || wildcard) {
550 		return *this;
551 	}
552 	// taking address
553 	else if (level < 0) {
554 		assert(level == -1);
555 		CVQualifiers qfer = *this;
556 		qfer.add_qualifiers(false, false);
557 		return qfer;
558 	}
559 	// dereference
560 	else {
561 		CVQualifiers qfer = *this;
562 		qfer.remove_qualifiers(level);
563 		return qfer;
564 	}
565 }
566 
567 /*
568  * check if the indirect depth of type matches qualifier size
569  */
570 bool
sanity_check(const Type * t) const571 CVQualifiers::sanity_check(const Type* t) const
572 {
573 	assert(t);
574 	int level = t->get_indirect_level();
575 	assert(level >= 0);
576 	return wildcard || (is_consts.size() == is_volatiles.size() && (static_cast<size_t>(level)+1) == is_consts.size());
577 }
578 
579 void
output_qualified_type(const Type * t,std::ostream & out) const580 CVQualifiers::output_qualified_type(const Type* t, std::ostream &out) const
581 {
582 	assert(t);
583 	assert(sanity_check(t));
584 	size_t i;
585 	const Type* base = t->get_base_type();
586 	for (i=0; i<is_consts.size(); i++) {
587 		if (i>0) {
588 			out << "*";
589 		}
590 		if (is_consts[i]) {
591 			if (!CGOptions::consts())
592 				assert(0);
593 			if (i > 0) out << " ";
594 			out << "const ";
595 		}
596 		if (is_volatiles[i]) {
597 			if (!CGOptions::volatiles())
598 				assert(0);
599 			if (i > 0) out << " ";
600 			out << "volatile ";
601 		}
602 		if (i==0) {
603 			base->Output(out);
604 			out << " ";
605 		}
606 	}
607 }
608 
609 bool
is_const_after_deref(int deref_level) const610 CVQualifiers::is_const_after_deref(int deref_level) const
611 {
612 	if (deref_level < 0) {
613 		return false;
614 	}
615 	size_t len = is_consts.size();
616 	assert(len > static_cast<size_t>(deref_level));
617 	return is_consts[len - deref_level - 1];
618 }
619 
620 bool
is_volatile_after_deref(int deref_level) const621 CVQualifiers::is_volatile_after_deref(int deref_level) const
622 {
623 	if (deref_level < 0) {
624 		return false;
625 	}
626 	size_t len = is_volatiles.size();
627 	assert(len > static_cast<size_t>(deref_level));
628 	/*
629 	if (len <= static_cast<size_t>(deref_level)) {
630 		cout << "len = " << len << ", deref_level = " << deref_level << std::endl;
631 		assert(0);
632 	}
633 	*/
634 	return is_volatiles[len - deref_level - 1];
635 }
636 
637 void
set_const(bool is_const,int pos)638 CVQualifiers::set_const(bool is_const, int pos)
639 {
640 	int len = is_consts.size();
641 	if (len > 0) {
642 		is_consts[len - pos - 1] = is_const;
643 	}
644 }
645 
646 void
set_volatile(bool is_volatile,int pos)647 CVQualifiers::set_volatile(bool is_volatile, int pos)
648 {
649 	int len = is_volatiles.size();
650 	if (len > 0) {
651 		is_volatiles[len - pos - 1] = is_volatile;
652 	}
653 }
654 
655 void
656 CVQualifiers::restrict(Effect::Access access, const CGContext& cg_context)
657 {
658 	if (access == Effect::WRITE) {
659 		set_const(false);
660 	}
661 	if (!cg_context.get_effect_context().is_side_effect_free()) {
662 		set_volatile(false);
663 	}
664 }
665 
666 /*
667  * For now, only used to generate all qualifiers for struct fields.
668  * Also, since we don't support fields with pointer types, we only
669  * enumerate the first level of qualifiers.
670  */
671 void
get_all_qualifiers(vector<CVQualifiers> & quals,unsigned int const_prob,unsigned int volatile_prob)672 CVQualifiers::get_all_qualifiers(vector<CVQualifiers> &quals, unsigned int const_prob, unsigned int volatile_prob)
673 {
674 	Enumerator<string> qual_enumerator;
675 	qual_enumerator.add_bool_elem("const_prob", const_prob);
676 	qual_enumerator.add_bool_elem("volatile_prob", volatile_prob);
677 	Enumerator<string> *i;
678 	for (i = qual_enumerator.begin(); i != qual_enumerator.end(); i = i->next()) {
679 		bool isConst = i->get_elem("const_prob") != 0;
680 		bool isVolatile = i->get_elem("volatile_prob") != 0;
681 
682 		vector<bool> consts;
683 		vector<bool> volatiles;
684 
685 		consts.push_back(isConst);
686 		volatiles.push_back(isVolatile);
687 		CVQualifiers qual(consts, volatiles);
688 
689 		quals.push_back(qual);
690 	}
691 }
692 
693 void
OutputFirstQuals(std::ostream & out) const694 CVQualifiers::OutputFirstQuals(std::ostream &out) const
695 {
696 	if (is_consts.size() > 0 && is_consts[0]) {
697 		if (!CGOptions::consts())
698 			assert(0);
699 		out << "const ";
700 	}
701 
702 	if (is_volatiles.size() > 0 && is_volatiles[0]) {
703 		if (!CGOptions::volatiles())
704 			assert(0);
705 		out << "volatile ";
706 	}
707 }
708 
709 void
output() const710 CVQualifiers::output() const
711 {
712 	size_t i;
713 	for (i=0; i<is_consts.size(); i++) {
714 		cout << is_consts[i] << " ";
715 	}
716 	cout << ", ";
717 	for (i=0; i<is_volatiles.size(); i++) {
718 		cout << is_volatiles[i] << " ";
719 	}
720 	cout << endl;
721 }
722