xref: /illumos-gate/usr/src/tools/smatch/src/builtin.c (revision d8109ce4330e1b8ad6c29f9fccacec969066bb9d)
1 /*
2  * builtin evaluation & expansion.
3  *
4  * Copyright (C) 2003 Transmeta Corp.
5  *               2003-2004 Linus Torvalds
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  */
25 
26 #include "expression.h"
27 #include "expand.h"
28 #include "symbol.h"
29 #include "compat/bswap.h"
30 
31 static int evaluate_to_int_const_expr(struct expression *expr)
32 {
33 	expr->ctype = &int_ctype;
34 	expr->flags |= CEF_SET_ICE;
35 	return 1;
36 }
37 
38 static int evaluate_pure_unop(struct expression *expr)
39 {
40 	struct expression *arg = first_expression(expr->args);
41 	int flags = arg->flags;
42 
43 	/*
44 	 * Allow such functions with a constant integer expression
45 	 * argument to be treated as a *constant* integer.
46 	 * This allow us to use them in switch() { case ...:
47 	 */
48 	flags |= (flags & CEF_ICE) ? CEF_SET_INT : 0;
49 	expr->flags = flags;
50 	return 1;
51 }
52 
53 
54 static int evaluate_expect(struct expression *expr)
55 {
56 	/* Should we evaluate it to return the type of the first argument? */
57 	expr->ctype = &int_ctype;
58 	return 1;
59 }
60 
61 static int arguments_choose(struct expression *expr)
62 {
63 	struct expression_list *arglist = expr->args;
64 	struct expression *arg;
65 	int i = 0;
66 
67 	FOR_EACH_PTR (arglist, arg) {
68 		if (!evaluate_expression(arg))
69 			return 0;
70 		i++;
71 	} END_FOR_EACH_PTR(arg);
72 	if (i < 3) {
73 		sparse_error(expr->pos,
74 			     "not enough arguments for __builtin_choose_expr");
75 		return 0;
76 	} if (i > 3) {
77 		sparse_error(expr->pos,
78 			     "too many arguments for __builtin_choose_expr");
79 		return 0;
80 	}
81 	return 1;
82 }
83 
84 static int evaluate_choose(struct expression *expr)
85 {
86 	struct expression_list *list = expr->args;
87 	struct expression *arg, *args[3];
88 	int n = 0;
89 
90 	/* there will be exactly 3; we'd already verified that */
91 	FOR_EACH_PTR(list, arg) {
92 		args[n++] = arg;
93 	} END_FOR_EACH_PTR(arg);
94 
95 	*expr = get_expression_value(args[0]) ? *args[1] : *args[2];
96 
97 	return 1;
98 }
99 
100 static int expand_expect(struct expression *expr, int cost)
101 {
102 	struct expression *arg = first_ptr_list((struct ptr_list *) expr->args);
103 
104 	if (arg)
105 		*expr = *arg;
106 	return 0;
107 }
108 
109 /*
110  * __builtin_warning() has type "int" and always returns 1,
111  * so that you can use it in conditionals or whatever
112  */
113 static int expand_warning(struct expression *expr, int cost)
114 {
115 	struct expression *arg;
116 	struct expression_list *arglist = expr->args;
117 
118 	FOR_EACH_PTR (arglist, arg) {
119 		/*
120 		 * Constant strings get printed out as a warning. By the
121 		 * time we get here, the EXPR_STRING has been fully
122 		 * evaluated, so by now it's an anonymous symbol with a
123 		 * string initializer.
124 		 *
125 		 * Just for the heck of it, allow any constant string
126 		 * symbol.
127 		 */
128 		if (arg->type == EXPR_SYMBOL) {
129 			struct symbol *sym = arg->symbol;
130 			if (sym->initializer && sym->initializer->type == EXPR_STRING) {
131 				struct string *string = sym->initializer->string;
132 				warning(expr->pos, "%*s", string->length-1, string->data);
133 			}
134 			continue;
135 		}
136 
137 		/*
138 		 * Any other argument is a conditional. If it's
139 		 * non-constant, or it is false, we exit and do
140 		 * not print any warning.
141 		 */
142 		if (arg->type != EXPR_VALUE)
143 			goto out;
144 		if (!arg->value)
145 			goto out;
146 	} END_FOR_EACH_PTR(arg);
147 out:
148 	expr->type = EXPR_VALUE;
149 	expr->value = 1;
150 	expr->taint = 0;
151 	return 0;
152 }
153 
154 /* The arguments are constant if the cost of all of them is zero */
155 static int expand_constant_p(struct expression *expr, int cost)
156 {
157 	expr->type = EXPR_VALUE;
158 	expr->value = !cost;
159 	expr->taint = 0;
160 	return 0;
161 }
162 
163 /* The arguments are safe, if their cost is less than SIDE_EFFECTS */
164 static int expand_safe_p(struct expression *expr, int cost)
165 {
166 	expr->type = EXPR_VALUE;
167 	expr->value = (cost < SIDE_EFFECTS);
168 	expr->taint = 0;
169 	return 0;
170 }
171 
172 static struct symbol_op constant_p_op = {
173 	.evaluate = evaluate_to_int_const_expr,
174 	.expand = expand_constant_p
175 };
176 
177 static struct symbol_op safe_p_op = {
178 	.evaluate = evaluate_to_int_const_expr,
179 	.expand = expand_safe_p
180 };
181 
182 static struct symbol_op warning_op = {
183 	.evaluate = evaluate_to_int_const_expr,
184 	.expand = expand_warning
185 };
186 
187 static struct symbol_op expect_op = {
188 	.evaluate = evaluate_expect,
189 	.expand = expand_expect
190 };
191 
192 static struct symbol_op choose_op = {
193 	.evaluate = evaluate_choose,
194 	.args = arguments_choose,
195 };
196 
197 /* The argument is constant and valid if the cost is zero */
198 static int expand_bswap(struct expression *expr, int cost)
199 {
200 	struct expression *arg;
201 	long long val;
202 
203 	if (cost)
204 		return cost;
205 
206 	/* the arguments number & type have already been checked */
207 	arg = first_expression(expr->args);
208 	val = get_expression_value_silent(arg);
209 	switch (expr->ctype->bit_size) {
210 	case 16: expr->value = bswap16(val); break;
211 	case 32: expr->value = bswap32(val); break;
212 	case 64: expr->value = bswap64(val); break;
213 	default: /* impossible error */
214 		return SIDE_EFFECTS;
215 	}
216 
217 	expr->type = EXPR_VALUE;
218 	expr->taint = 0;
219 	return 0;
220 }
221 
222 static struct symbol_op bswap_op = {
223 	.evaluate = evaluate_pure_unop,
224 	.expand = expand_bswap,
225 };
226 
227 
228 /*
229  * Builtin functions
230  */
231 static struct symbol builtin_fn_type = { .type = SYM_FN /* , .variadic =1 */ };
232 static struct sym_init {
233 	const char *name;
234 	struct symbol *base_type;
235 	unsigned int modifiers;
236 	struct symbol_op *op;
237 } builtins_table[] = {
238 	{ "__builtin_constant_p", &builtin_fn_type, MOD_TOPLEVEL, &constant_p_op },
239 	{ "__builtin_safe_p", &builtin_fn_type, MOD_TOPLEVEL, &safe_p_op },
240 	{ "__builtin_warning", &builtin_fn_type, MOD_TOPLEVEL, &warning_op },
241 	{ "__builtin_expect", &builtin_fn_type, MOD_TOPLEVEL, &expect_op },
242 	{ "__builtin_choose_expr", &builtin_fn_type, MOD_TOPLEVEL, &choose_op },
243 	{ "__builtin_bswap16", NULL, MOD_TOPLEVEL, &bswap_op },
244 	{ "__builtin_bswap32", NULL, MOD_TOPLEVEL, &bswap_op },
245 	{ "__builtin_bswap64", NULL, MOD_TOPLEVEL, &bswap_op },
246 	{ NULL,		NULL,		0 }
247 };
248 
249 void init_builtins(int stream)
250 {
251 	struct sym_init *ptr;
252 
253 	builtin_fn_type.variadic = 1;
254 	for (ptr = builtins_table; ptr->name; ptr++) {
255 		struct symbol *sym;
256 		sym = create_symbol(stream, ptr->name, SYM_NODE, NS_SYMBOL);
257 		sym->ctype.base_type = ptr->base_type;
258 		sym->ctype.modifiers = ptr->modifiers;
259 		sym->op = ptr->op;
260 	}
261 }
262