sval: create temporary drange_sval_to_drange()
[smatch.git] / smatch_sval.c
blob16fdb72c71d36ed8f559fbdc6bf40ec0eb7668dd
1 /*
2 * smatch/smatch_sval.c
4 * Copyright (C) 2012 Oracle.
6 * Licensed under the Open Software License version 1.1
9 * Basically the point of sval is that it can hold both ULLONG_MAX and
10 * LLONG_MIN. If it is an unsigned type then we use sval.uvalue or if it is
11 * signed we use sval.value.
13 * I considered just using one bit to store whether the value was signed vs
14 * unsigned but I think it might help to have the type information so we know
15 * how to do type promotion.
19 #include "smatch.h"
20 #include "smatch_slist.h"
21 #include "smatch_extra.h"
23 __ALLOCATOR(sval_t, "svals", sval);
25 sval_t *sval_alloc(sval_t sval)
27 sval_t *ret;
29 ret = __alloc_sval(0);
30 *ret = sval;
31 return ret;
34 sval_t *sval_alloc_permanent(sval_t sval)
36 sval_t *ret;
38 ret = malloc(sizeof(*ret));
39 *ret = sval;
40 return ret;
43 sval_t sval_blank(struct expression *expr)
45 sval_t ret;
47 ret.type = get_type(expr);
48 if (!ret.type)
49 ret.type = &llong_ctype;
50 ret.value = 123456789;
52 return ret;
55 sval_t sval_from_val(struct expression *expr, long long val)
57 sval_t ret;
59 ret = sval_blank(expr);
60 ret.value = val;
61 ret = sval_cast(ret, expr);
63 return ret;
66 int sval_unsigned(sval_t sval)
68 return type_unsigned(sval.type);
71 int sval_signed(sval_t sval)
73 return !type_unsigned(sval.type);
76 int sval_bits(sval_t sval)
78 if (!sval.type)
79 return 32;
80 return sval.type->bit_size;
83 int sval_is_min(sval_t sval)
85 sval_t min = sval_type_min(sval.type);
87 if (sval_unsigned(sval)) {
88 if (sval.uvalue == 0)
89 return 1;
90 return 0;
92 /* return true for less than min as well */
93 return (sval.value <= min.value);
96 int sval_is_max(sval_t sval)
98 sval_t max = sval_type_min(sval.type);
100 if (sval_unsigned(sval))
101 return (sval.uvalue >= max.value);
102 return (sval.value >= max.value);
106 * Casts the values and then does a compare. Returns -1 if one is smaller, 0 if
107 * they are the same and 1 if two is larger.
109 int sval_cmp(sval_t one, sval_t two)
111 /* fix me handle type promotion and unsigned values */
112 if (one.value < two.value)
113 return -1;
114 if (one.value == two.value)
115 return 0;
116 return 1;
119 int sval_cmp_val(sval_t one, long long val)
121 if (one.value < val)
122 return -1;
123 if (one.value == val)
124 return 0;
125 return 1;
128 sval_t sval_cast(sval_t sval, struct expression *expr)
130 sval_t ret;
132 ret = sval_blank(expr);
133 switch (sval_bits(ret)) {
134 case 8:
135 if (sval_unsigned(ret))
136 ret.value = (long long)(unsigned char)sval.value;
137 else
138 ret.value = (long long)(char)sval.value;
139 break;
140 case 16:
141 if (sval_unsigned(ret))
142 ret.value = (long long)(unsigned short)sval.value;
143 else
144 ret.value = (long long)(short)sval.value;
145 break;
146 case 32:
147 if (sval_unsigned(ret))
148 ret.value = (long long)(unsigned int)sval.value;
149 else
150 ret.value = (long long)(int)sval.value;
151 break;
152 default:
153 ret.value = sval.value;
155 return ret;
159 sval_t sval_preop(sval_t sval, int op)
161 switch (op) {
162 case '!':
163 sval.value = !sval.value;
164 break;
165 case '~':
166 sval.value = ~sval.value;
167 /* fixme: should probably cast this here */
168 break;
169 case '-':
170 sval.value = -sval.value;
171 break;
173 return sval;
176 sval_t sval_binop(sval_t left, int op, sval_t right)
178 sval_t ret;
180 /* fixme: these need to have proper type promotions */
181 ret.type = left.type;
182 switch (op) {
183 case '*':
184 ret.value = left.value * right.value;
185 break;
186 case '/':
187 if (right.value == 0) {
188 sm_msg("internal error: %s: divide by zero", __func__);
189 ret.value = 123456789;
190 } else {
191 ret.value = left.value / right.value;
193 break;
194 case '+':
195 ret.value = left.value + right.value;
196 break;
197 case '-':
198 ret.value = left.value - right.value;
199 break;
200 case '%':
201 if (right.value == 0) {
202 sm_msg("internal error: %s: MOD by zero", __func__);
203 ret.value = 123456789;
204 } else {
205 ret.value = left.value % right.value;
207 break;
208 case '|':
209 ret.value = left.value | right.value;
210 break;
211 case '&':
212 ret.value = left.value & right.value;
213 break;
214 case SPECIAL_RIGHTSHIFT:
215 ret.value = left.value >> right.value;
216 break;
217 case SPECIAL_LEFTSHIFT:
218 ret.value = left.value << right.value;
219 break;
220 case '^':
221 ret.value = left.value ^ right.value;
222 break;
223 default:
224 sm_msg("internal error: %s: unhandled binop %s", __func__,
225 show_special(op));
226 ret.value = 1234567;
228 return ret;
231 const char *sval_to_str(sval_t sval)
233 char buf[30];
235 if (sval_unsigned(sval) && sval.value == ULLONG_MAX)
236 return "u64max";
237 if (sval.value == LLONG_MAX)
238 return "s64max";
239 if (sval_unsigned(sval) && sval.value == UINT_MAX)
240 return "u32max";
241 if (sval.value == INT_MAX)
242 return "s32max";
243 if (sval_unsigned(sval) && sval.value == USHRT_MAX)
244 return "u16max";
246 if ((sval.type == &sshort_ctype || sval.type == &short_ctype) && sval.value == SHRT_MIN)
247 return "s16min";
248 if ((sval.type == &sint_ctype || sval.type == &int_ctype) && sval.value == INT_MIN)
249 return "s32min";
250 if (sval_signed(sval) && sval.value == LLONG_MIN)
251 return "s64min";
253 if (sval_unsigned(sval))
254 snprintf(buf, sizeof(buf), "%llu", sval.value);
255 else if (sval.value < 0)
256 snprintf(buf, sizeof(buf), "(%lld)", sval.value);
257 else
258 snprintf(buf, sizeof(buf), "%lld", sval.value);
260 return alloc_sname(buf);
264 * This function is for compatibility. Eventually everything will use svals
265 * and we can get rid of whole_range.max.
267 long long sval_to_ll(sval_t sval)
269 if (sval_unsigned(sval) && sval.value == ULLONG_MAX)
270 return whole_range.max;
271 return sval.value;
274 sval_t ll_to_sval(long long val)
276 sval_t ret;
278 ret.type = &llong_ctype;
279 ret.value = val;
280 return ret;
283 static void free_svals(struct symbol *sym)
285 clear_sval_alloc();
288 void register_sval(int my_id)
290 add_hook(&free_svals, END_FUNC_HOOK);