xref: /illumos-gate/usr/src/tools/smatch/src/expand.c (revision c85f09cc)
11f5207b7SJohn Levon /*
21f5207b7SJohn Levon  * sparse/expand.c
31f5207b7SJohn Levon  *
41f5207b7SJohn Levon  * Copyright (C) 2003 Transmeta Corp.
51f5207b7SJohn Levon  *               2003-2004 Linus Torvalds
61f5207b7SJohn Levon  *
71f5207b7SJohn Levon  * Permission is hereby granted, free of charge, to any person obtaining a copy
81f5207b7SJohn Levon  * of this software and associated documentation files (the "Software"), to deal
91f5207b7SJohn Levon  * in the Software without restriction, including without limitation the rights
101f5207b7SJohn Levon  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
111f5207b7SJohn Levon  * copies of the Software, and to permit persons to whom the Software is
121f5207b7SJohn Levon  * furnished to do so, subject to the following conditions:
131f5207b7SJohn Levon  *
141f5207b7SJohn Levon  * The above copyright notice and this permission notice shall be included in
151f5207b7SJohn Levon  * all copies or substantial portions of the Software.
161f5207b7SJohn Levon  *
171f5207b7SJohn Levon  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
181f5207b7SJohn Levon  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
191f5207b7SJohn Levon  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
201f5207b7SJohn Levon  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
211f5207b7SJohn Levon  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
221f5207b7SJohn Levon  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
231f5207b7SJohn Levon  * THE SOFTWARE.
241f5207b7SJohn Levon  *
251f5207b7SJohn Levon  * expand constant expressions.
261f5207b7SJohn Levon  */
271f5207b7SJohn Levon #include <stdlib.h>
281f5207b7SJohn Levon #include <stdarg.h>
291f5207b7SJohn Levon #include <stddef.h>
301f5207b7SJohn Levon #include <stdio.h>
311f5207b7SJohn Levon #include <string.h>
321f5207b7SJohn Levon #include <ctype.h>
331f5207b7SJohn Levon #include <unistd.h>
341f5207b7SJohn Levon #include <fcntl.h>
351f5207b7SJohn Levon #include <limits.h>
361f5207b7SJohn Levon 
371f5207b7SJohn Levon #include "lib.h"
381f5207b7SJohn Levon #include "allocate.h"
391f5207b7SJohn Levon #include "parse.h"
401f5207b7SJohn Levon #include "token.h"
411f5207b7SJohn Levon #include "symbol.h"
421f5207b7SJohn Levon #include "target.h"
431f5207b7SJohn Levon #include "expression.h"
44*c85f09ccSJohn Levon #include "evaluate.h"
451f5207b7SJohn Levon #include "expand.h"
461f5207b7SJohn Levon 
471f5207b7SJohn Levon 
481f5207b7SJohn Levon static int expand_expression(struct expression *);
491f5207b7SJohn Levon static int expand_statement(struct statement *);
50*c85f09ccSJohn Levon 
51*c85f09ccSJohn Levon // If set, don't issue a warning on divide-by-0, invalid shift, ...
52*c85f09ccSJohn Levon // and don't mark the expression as erroneous but leave it as-is.
53*c85f09ccSJohn Levon // This allows testing some characteristics of the expression
54*c85f09ccSJohn Levon // without creating any side-effects (e.g.: is_zero_constant()).
551f5207b7SJohn Levon static int conservative;
561f5207b7SJohn Levon 
expand_symbol_expression(struct expression * expr)571f5207b7SJohn Levon static int expand_symbol_expression(struct expression *expr)
581f5207b7SJohn Levon {
591f5207b7SJohn Levon 	struct symbol *sym = expr->symbol;
601f5207b7SJohn Levon 
611f5207b7SJohn Levon 	if (sym == &zero_int) {
621f5207b7SJohn Levon 		if (Wundef)
631f5207b7SJohn Levon 			warning(expr->pos, "undefined preprocessor identifier '%s'", show_ident(expr->symbol_name));
641f5207b7SJohn Levon 		expr->type = EXPR_VALUE;
651f5207b7SJohn Levon 		expr->value = 0;
661f5207b7SJohn Levon 		expr->taint = 0;
671f5207b7SJohn Levon 		return 0;
681f5207b7SJohn Levon 	}
691f5207b7SJohn Levon 	/* The cost of a symbol expression is lower for on-stack symbols */
701f5207b7SJohn Levon 	return (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN)) ? 2 : 1;
711f5207b7SJohn Levon }
721f5207b7SJohn Levon 
get_longlong(struct expression * expr)731f5207b7SJohn Levon static long long get_longlong(struct expression *expr)
741f5207b7SJohn Levon {
751f5207b7SJohn Levon 	int no_expand = expr->ctype->ctype.modifiers & MOD_UNSIGNED;
761f5207b7SJohn Levon 	long long mask = 1ULL << (expr->ctype->bit_size - 1);
771f5207b7SJohn Levon 	long long value = expr->value;
781f5207b7SJohn Levon 	long long ormask, andmask;
791f5207b7SJohn Levon 
801f5207b7SJohn Levon 	if (!(value & mask))
811f5207b7SJohn Levon 		no_expand = 1;
821f5207b7SJohn Levon 	andmask = mask | (mask-1);
831f5207b7SJohn Levon 	ormask = ~andmask;
841f5207b7SJohn Levon 	if (no_expand)
851f5207b7SJohn Levon 		ormask = 0;
861f5207b7SJohn Levon 	return (value & andmask) | ormask;
871f5207b7SJohn Levon }
881f5207b7SJohn Levon 
cast_value(struct expression * expr,struct symbol * newtype,struct expression * old,struct symbol * oldtype)891f5207b7SJohn Levon void cast_value(struct expression *expr, struct symbol *newtype,
901f5207b7SJohn Levon 		struct expression *old, struct symbol *oldtype)
911f5207b7SJohn Levon {
921f5207b7SJohn Levon 	int old_size = oldtype->bit_size;
931f5207b7SJohn Levon 	int new_size = newtype->bit_size;
941f5207b7SJohn Levon 	long long value, mask, signmask;
951f5207b7SJohn Levon 	long long oldmask, oldsignmask, dropped;
961f5207b7SJohn Levon 
971f5207b7SJohn Levon 	if (is_float_type(newtype) || is_float_type(oldtype))
981f5207b7SJohn Levon 		goto Float;
991f5207b7SJohn Levon 
1001f5207b7SJohn Levon 	// For pointers and integers, we can just move the value around
1011f5207b7SJohn Levon 	expr->type = EXPR_VALUE;
1021f5207b7SJohn Levon 	expr->taint = old->taint;
1031f5207b7SJohn Levon 	if (old_size == new_size) {
1041f5207b7SJohn Levon 		expr->value = old->value;
1051f5207b7SJohn Levon 		return;
1061f5207b7SJohn Levon 	}
1071f5207b7SJohn Levon 
1081f5207b7SJohn Levon 	// expand it to the full "long long" value
1091f5207b7SJohn Levon 	value = get_longlong(old);
1101f5207b7SJohn Levon 
1111f5207b7SJohn Levon Int:
1121f5207b7SJohn Levon 	// _Bool requires a zero test rather than truncation.
1131f5207b7SJohn Levon 	if (is_bool_type(newtype)) {
1141f5207b7SJohn Levon 		expr->value = !!value;
1151f5207b7SJohn Levon 		if (!conservative && value != 0 && value != 1)
1161f5207b7SJohn Levon 			warning(old->pos, "odd constant _Bool cast (%llx becomes 1)", value);
1171f5207b7SJohn Levon 		return;
1181f5207b7SJohn Levon 	}
1191f5207b7SJohn Levon 
1201f5207b7SJohn Levon 	// Truncate it to the new size
1211f5207b7SJohn Levon 	signmask = 1ULL << (new_size-1);
1221f5207b7SJohn Levon 	mask = signmask | (signmask-1);
1231f5207b7SJohn Levon 	expr->value = value & mask;
1241f5207b7SJohn Levon 
1251f5207b7SJohn Levon 	// Stop here unless checking for truncation
1261f5207b7SJohn Levon 	if (!Wcast_truncate || conservative)
1271f5207b7SJohn Levon 		return;
1281f5207b7SJohn Levon 
1291f5207b7SJohn Levon 	// Check if we dropped any bits..
1301f5207b7SJohn Levon 	oldsignmask = 1ULL << (old_size-1);
1311f5207b7SJohn Levon 	oldmask = oldsignmask | (oldsignmask-1);
1321f5207b7SJohn Levon 	dropped = oldmask & ~mask;
1331f5207b7SJohn Levon 
1341f5207b7SJohn Levon 	// OK if the bits were (and still are) purely sign bits
1351f5207b7SJohn Levon 	if (value & dropped) {
1361f5207b7SJohn Levon 		if (!(value & oldsignmask) || !(value & signmask) || (value & dropped) != dropped)
1371f5207b7SJohn Levon 			warning(old->pos, "cast truncates bits from constant value (%llx becomes %llx)",
1381f5207b7SJohn Levon 				value & oldmask,
1391f5207b7SJohn Levon 				value & mask);
1401f5207b7SJohn Levon 	}
1411f5207b7SJohn Levon 	return;
1421f5207b7SJohn Levon 
1431f5207b7SJohn Levon Float:
1441f5207b7SJohn Levon 	if (!is_float_type(newtype)) {
1451f5207b7SJohn Levon 		value = (long long)old->fvalue;
1461f5207b7SJohn Levon 		expr->type = EXPR_VALUE;
1471f5207b7SJohn Levon 		expr->taint = 0;
1481f5207b7SJohn Levon 		goto Int;
1491f5207b7SJohn Levon 	}
1501f5207b7SJohn Levon 
1511f5207b7SJohn Levon 	if (!is_float_type(oldtype))
1521f5207b7SJohn Levon 		expr->fvalue = (long double)get_longlong(old);
1531f5207b7SJohn Levon 	else
1541f5207b7SJohn Levon 		expr->fvalue = old->fvalue;
1551f5207b7SJohn Levon 
1561f5207b7SJohn Levon 	if (!(newtype->ctype.modifiers & MOD_LONGLONG) && \
1571f5207b7SJohn Levon 	    !(newtype->ctype.modifiers & MOD_LONGLONGLONG)) {
1581f5207b7SJohn Levon 		if ((newtype->ctype.modifiers & MOD_LONG))
1591f5207b7SJohn Levon 			expr->fvalue = (double)expr->fvalue;
1601f5207b7SJohn Levon 		else
1611f5207b7SJohn Levon 			expr->fvalue = (float)expr->fvalue;
1621f5207b7SJohn Levon 	}
1631f5207b7SJohn Levon 	expr->type = EXPR_FVALUE;
1641f5207b7SJohn Levon }
1651f5207b7SJohn Levon 
warn_shift_count(struct expression * expr,struct symbol * ctype,long long count)166*c85f09ccSJohn Levon static void warn_shift_count(struct expression *expr, struct symbol *ctype, long long count)
1671f5207b7SJohn Levon {
168*c85f09ccSJohn Levon 	if (count < 0) {
169*c85f09ccSJohn Levon 		if (!Wshift_count_negative)
170*c85f09ccSJohn Levon 			return;
171*c85f09ccSJohn Levon 		warning(expr->pos, "shift count is negative (%lld)", count);
172*c85f09ccSJohn Levon 		return;
173*c85f09ccSJohn Levon 	}
174*c85f09ccSJohn Levon 	if (ctype->type == SYM_NODE)
175*c85f09ccSJohn Levon 		ctype = ctype->ctype.base_type;
176*c85f09ccSJohn Levon 
177*c85f09ccSJohn Levon 	if (!Wshift_count_overflow)
178*c85f09ccSJohn Levon 		return;
179*c85f09ccSJohn Levon 	warning(expr->pos, "shift too big (%llu) for type %s", count, show_typename(ctype));
180*c85f09ccSJohn Levon }
181*c85f09ccSJohn Levon 
182*c85f09ccSJohn Levon /* Return true if constant shift size is valid */
check_shift_count(struct expression * expr,struct expression * right)183*c85f09ccSJohn Levon static bool check_shift_count(struct expression *expr, struct expression *right)
184*c85f09ccSJohn Levon {
185*c85f09ccSJohn Levon 	struct symbol *ctype = expr->ctype;
186*c85f09ccSJohn Levon 	long long count = get_longlong(right);
187*c85f09ccSJohn Levon 
188*c85f09ccSJohn Levon 	if (count >= 0 && count < ctype->bit_size)
189*c85f09ccSJohn Levon 		return true;
190*c85f09ccSJohn Levon 	if (!conservative)
191*c85f09ccSJohn Levon 		warn_shift_count(expr, ctype, count);
192*c85f09ccSJohn Levon 	return false;
1931f5207b7SJohn Levon }
1941f5207b7SJohn Levon 
1951f5207b7SJohn Levon /*
1961f5207b7SJohn Levon  * CAREFUL! We need to get the size and sign of the
1971f5207b7SJohn Levon  * result right!
1981f5207b7SJohn Levon  */
1991f5207b7SJohn Levon #define CONVERT(op,s)	(((op)<<1)+(s))
2001f5207b7SJohn Levon #define SIGNED(op)	CONVERT(op, 1)
2011f5207b7SJohn Levon #define UNSIGNED(op)	CONVERT(op, 0)
simplify_int_binop(struct expression * expr,struct symbol * ctype)2021f5207b7SJohn Levon static int simplify_int_binop(struct expression *expr, struct symbol *ctype)
2031f5207b7SJohn Levon {
2041f5207b7SJohn Levon 	struct expression *left = expr->left, *right = expr->right;
2051f5207b7SJohn Levon 	unsigned long long v, l, r, mask;
2061f5207b7SJohn Levon 	signed long long sl, sr;
2071f5207b7SJohn Levon 	int is_signed;
2081f5207b7SJohn Levon 
2091f5207b7SJohn Levon 	if (right->type != EXPR_VALUE)
2101f5207b7SJohn Levon 		return 0;
2111f5207b7SJohn Levon 	r = right->value;
2121f5207b7SJohn Levon 	if (expr->op == SPECIAL_LEFTSHIFT || expr->op == SPECIAL_RIGHTSHIFT) {
213*c85f09ccSJohn Levon 		if (!check_shift_count(expr, right))
214*c85f09ccSJohn Levon 			return 0;
2151f5207b7SJohn Levon 	}
2161f5207b7SJohn Levon 	if (left->type != EXPR_VALUE)
2171f5207b7SJohn Levon 		return 0;
2181f5207b7SJohn Levon 	l = left->value; r = right->value;
2191f5207b7SJohn Levon 	is_signed = !(ctype->ctype.modifiers & MOD_UNSIGNED);
2201f5207b7SJohn Levon 	mask = 1ULL << (ctype->bit_size-1);
2211f5207b7SJohn Levon 	sl = l; sr = r;
2221f5207b7SJohn Levon 	if (is_signed && (sl & mask))
2231f5207b7SJohn Levon 		sl |= ~(mask-1);
2241f5207b7SJohn Levon 	if (is_signed && (sr & mask))
2251f5207b7SJohn Levon 		sr |= ~(mask-1);
2261f5207b7SJohn Levon 
2271f5207b7SJohn Levon 	switch (CONVERT(expr->op,is_signed)) {
2281f5207b7SJohn Levon 	case SIGNED('+'):
2291f5207b7SJohn Levon 	case UNSIGNED('+'):
2301f5207b7SJohn Levon 		v = l + r;
2311f5207b7SJohn Levon 		break;
2321f5207b7SJohn Levon 
2331f5207b7SJohn Levon 	case SIGNED('-'):
2341f5207b7SJohn Levon 	case UNSIGNED('-'):
2351f5207b7SJohn Levon 		v = l - r;
2361f5207b7SJohn Levon 		break;
2371f5207b7SJohn Levon 
2381f5207b7SJohn Levon 	case SIGNED('&'):
2391f5207b7SJohn Levon 	case UNSIGNED('&'):
2401f5207b7SJohn Levon 		v = l & r;
2411f5207b7SJohn Levon 		break;
2421f5207b7SJohn Levon 
2431f5207b7SJohn Levon 	case SIGNED('|'):
2441f5207b7SJohn Levon 	case UNSIGNED('|'):
2451f5207b7SJohn Levon 		v = l | r;
2461f5207b7SJohn Levon 		break;
2471f5207b7SJohn Levon 
2481f5207b7SJohn Levon 	case SIGNED('^'):
2491f5207b7SJohn Levon 	case UNSIGNED('^'):
2501f5207b7SJohn Levon 		v = l ^ r;
2511f5207b7SJohn Levon 		break;
2521f5207b7SJohn Levon 
2531f5207b7SJohn Levon 	case SIGNED('*'):
2541f5207b7SJohn Levon 		v = sl * sr;
2551f5207b7SJohn Levon 		break;
2561f5207b7SJohn Levon 
2571f5207b7SJohn Levon 	case UNSIGNED('*'):
2581f5207b7SJohn Levon 		v = l * r;
2591f5207b7SJohn Levon 		break;
2601f5207b7SJohn Levon 
2611f5207b7SJohn Levon 	case SIGNED('/'):
2621f5207b7SJohn Levon 		if (!r)
2631f5207b7SJohn Levon 			goto Div;
2641f5207b7SJohn Levon 		if (l == mask && sr == -1)
2651f5207b7SJohn Levon 			goto Overflow;
2661f5207b7SJohn Levon 		v = sl / sr;
2671f5207b7SJohn Levon 		break;
2681f5207b7SJohn Levon 
2691f5207b7SJohn Levon 	case UNSIGNED('/'):
2701f5207b7SJohn Levon 		if (!r) goto Div;
2711f5207b7SJohn Levon 		v = l / r;
2721f5207b7SJohn Levon 		break;
2731f5207b7SJohn Levon 
2741f5207b7SJohn Levon 	case SIGNED('%'):
2751f5207b7SJohn Levon 		if (!r)
2761f5207b7SJohn Levon 			goto Div;
2771f5207b7SJohn Levon 		if (l == mask && sr == -1)
2781f5207b7SJohn Levon 			goto Overflow;
2791f5207b7SJohn Levon 		v = sl % sr;
2801f5207b7SJohn Levon 		break;
2811f5207b7SJohn Levon 
2821f5207b7SJohn Levon 	case UNSIGNED('%'):
2831f5207b7SJohn Levon 		if (!r) goto Div;
2841f5207b7SJohn Levon 		v = l % r;
2851f5207b7SJohn Levon 		break;
2861f5207b7SJohn Levon 
2871f5207b7SJohn Levon 	case SIGNED(SPECIAL_LEFTSHIFT):
2881f5207b7SJohn Levon 	case UNSIGNED(SPECIAL_LEFTSHIFT):
2891f5207b7SJohn Levon 		v = l << r;
2901f5207b7SJohn Levon 		break;
2911f5207b7SJohn Levon 
2921f5207b7SJohn Levon 	case SIGNED(SPECIAL_RIGHTSHIFT):
2931f5207b7SJohn Levon 		v = sl >> r;
2941f5207b7SJohn Levon 		break;
2951f5207b7SJohn Levon 
2961f5207b7SJohn Levon 	case UNSIGNED(SPECIAL_RIGHTSHIFT):
2971f5207b7SJohn Levon 		v = l >> r;
2981f5207b7SJohn Levon 		break;
2991f5207b7SJohn Levon 
3001f5207b7SJohn Levon 	default:
3011f5207b7SJohn Levon 		return 0;
3021f5207b7SJohn Levon 	}
3031f5207b7SJohn Levon 	mask = mask | (mask-1);
3041f5207b7SJohn Levon 	expr->value = v & mask;
3051f5207b7SJohn Levon 	expr->type = EXPR_VALUE;
3061f5207b7SJohn Levon 	expr->taint = left->taint | right->taint;
3071f5207b7SJohn Levon 	return 1;
3081f5207b7SJohn Levon Div:
3091f5207b7SJohn Levon 	if (!conservative)
3101f5207b7SJohn Levon 		warning(expr->pos, "division by zero");
3111f5207b7SJohn Levon 	return 0;
3121f5207b7SJohn Levon Overflow:
3131f5207b7SJohn Levon 	if (!conservative)
3141f5207b7SJohn Levon 		warning(expr->pos, "constant integer operation overflow");
3151f5207b7SJohn Levon 	return 0;
3161f5207b7SJohn Levon }
3171f5207b7SJohn Levon 
simplify_cmp_binop(struct expression * expr,struct symbol * ctype)3181f5207b7SJohn Levon static int simplify_cmp_binop(struct expression *expr, struct symbol *ctype)
3191f5207b7SJohn Levon {
3201f5207b7SJohn Levon 	struct expression *left = expr->left, *right = expr->right;
3211f5207b7SJohn Levon 	unsigned long long l, r, mask;
3221f5207b7SJohn Levon 	signed long long sl, sr;
3231f5207b7SJohn Levon 
3241f5207b7SJohn Levon 	if (left->type != EXPR_VALUE || right->type != EXPR_VALUE)
3251f5207b7SJohn Levon 		return 0;
3261f5207b7SJohn Levon 	l = left->value; r = right->value;
3271f5207b7SJohn Levon 	mask = 1ULL << (ctype->bit_size-1);
3281f5207b7SJohn Levon 	sl = l; sr = r;
3291f5207b7SJohn Levon 	if (sl & mask)
3301f5207b7SJohn Levon 		sl |= ~(mask-1);
3311f5207b7SJohn Levon 	if (sr & mask)
3321f5207b7SJohn Levon 		sr |= ~(mask-1);
3331f5207b7SJohn Levon 	switch (expr->op) {
3341f5207b7SJohn Levon 	case '<':		expr->value = sl < sr; break;
3351f5207b7SJohn Levon 	case '>':		expr->value = sl > sr; break;
3361f5207b7SJohn Levon 	case SPECIAL_LTE:	expr->value = sl <= sr; break;
3371f5207b7SJohn Levon 	case SPECIAL_GTE:	expr->value = sl >= sr; break;
3381f5207b7SJohn Levon 	case SPECIAL_EQUAL:	expr->value = l == r; break;
3391f5207b7SJohn Levon 	case SPECIAL_NOTEQUAL:	expr->value = l != r; break;
3401f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LT:expr->value = l < r; break;
3411f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_GT:expr->value = l > r; break;
3421f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_LTE:expr->value = l <= r; break;
3431f5207b7SJohn Levon 	case SPECIAL_UNSIGNED_GTE:expr->value = l >= r; break;
3441f5207b7SJohn Levon 	}
3451f5207b7SJohn Levon 	expr->type = EXPR_VALUE;
3461f5207b7SJohn Levon 	expr->taint = left->taint | right->taint;
3471f5207b7SJohn Levon 	return 1;
3481f5207b7SJohn Levon }
3491f5207b7SJohn Levon 
simplify_float_binop(struct expression * expr)3501f5207b7SJohn Levon static int simplify_float_binop(struct expression *expr)
3511f5207b7SJohn Levon {
3521f5207b7SJohn Levon 	struct expression *left = expr->left, *right = expr->right;
3531f5207b7SJohn Levon 	unsigned long mod = expr->ctype->ctype.modifiers;
3541f5207b7SJohn Levon 	long double l, r, res;
3551f5207b7SJohn Levon 
3561f5207b7SJohn Levon 	if (left->type != EXPR_FVALUE || right->type != EXPR_FVALUE)
3571f5207b7SJohn Levon 		return 0;
3581f5207b7SJohn Levon 
3591f5207b7SJohn Levon 	l = left->fvalue;
3601f5207b7SJohn Levon 	r = right->fvalue;
3611f5207b7SJohn Levon 
3621f5207b7SJohn Levon 	if (mod & MOD_LONGLONG) {
3631f5207b7SJohn Levon 		switch (expr->op) {
3641f5207b7SJohn Levon 		case '+':	res = l + r; break;
3651f5207b7SJohn Levon 		case '-':	res = l - r; break;
3661f5207b7SJohn Levon 		case '*':	res = l * r; break;
3671f5207b7SJohn Levon 		case '/':	if (!r) goto Div;
3681f5207b7SJohn Levon 				res = l / r; break;
3691f5207b7SJohn Levon 		default: return 0;
3701f5207b7SJohn Levon 		}
3711f5207b7SJohn Levon 	} else if (mod & MOD_LONG) {
3721f5207b7SJohn Levon 		switch (expr->op) {
3731f5207b7SJohn Levon 		case '+':	res = (double) l + (double) r; break;
3741f5207b7SJohn Levon 		case '-':	res = (double) l - (double) r; break;
3751f5207b7SJohn Levon 		case '*':	res = (double) l * (double) r; break;
3761f5207b7SJohn Levon 		case '/':	if (!r) goto Div;
3771f5207b7SJohn Levon 				res = (double) l / (double) r; break;
3781f5207b7SJohn Levon 		default: return 0;
3791f5207b7SJohn Levon 		}
3801f5207b7SJohn Levon 	} else {
3811f5207b7SJohn Levon 		switch (expr->op) {
3821f5207b7SJohn Levon 		case '+':	res = (float)l + (float)r; break;
3831f5207b7SJohn Levon 		case '-':	res = (float)l - (float)r; break;
3841f5207b7SJohn Levon 		case '*':	res = (float)l * (float)r; break;
3851f5207b7SJohn Levon 		case '/':	if (!r) goto Div;
3861f5207b7SJohn Levon 				res = (float)l / (float)r; break;
3871f5207b7SJohn Levon 		default: return 0;
3881f5207b7SJohn Levon 		}
3891f5207b7SJohn Levon 	}
3901f5207b7SJohn Levon 	expr->type = EXPR_FVALUE;
3911f5207b7SJohn Levon 	expr->fvalue = res;
3921f5207b7SJohn Levon 	return 1;
3931f5207b7SJohn Levon Div:
3941f5207b7SJohn Levon 	if (!conservative)
3951f5207b7SJohn Levon 		warning(expr->pos, "division by zero");
3961f5207b7SJohn Levon 	return 0;
3971f5207b7SJohn Levon }
3981f5207b7SJohn Levon 
simplify_float_cmp(struct expression * expr,struct symbol * ctype)3991f5207b7SJohn Levon static int simplify_float_cmp(struct expression *expr, struct symbol *ctype)
4001f5207b7SJohn Levon {
4011f5207b7SJohn Levon 	struct expression *left = expr->left, *right = expr->right;
4021f5207b7SJohn Levon 	long double l, r;
4031f5207b7SJohn Levon 
4041f5207b7SJohn Levon 	if (left->type != EXPR_FVALUE || right->type != EXPR_FVALUE)
4051f5207b7SJohn Levon 		return 0;
4061f5207b7SJohn Levon 
4071f5207b7SJohn Levon 	l = left->fvalue;
4081f5207b7SJohn Levon 	r = right->fvalue;
4091f5207b7SJohn Levon 	switch (expr->op) {
4101f5207b7SJohn Levon 	case '<':		expr->value = l < r; break;
4111f5207b7SJohn Levon 	case '>':		expr->value = l > r; break;
4121f5207b7SJohn Levon 	case SPECIAL_LTE:	expr->value = l <= r; break;
4131f5207b7SJohn Levon 	case SPECIAL_GTE:	expr->value = l >= r; break;
4141f5207b7SJohn Levon 	case SPECIAL_EQUAL:	expr->value = l == r; break;
4151f5207b7SJohn Levon 	case SPECIAL_NOTEQUAL:	expr->value = l != r; break;
4161f5207b7SJohn Levon 	}
4171f5207b7SJohn Levon 	expr->type = EXPR_VALUE;
4181f5207b7SJohn Levon 	expr->taint = 0;
4191f5207b7SJohn Levon 	return 1;
4201f5207b7SJohn Levon }
4211f5207b7SJohn Levon 
expand_binop(struct expression * expr)4221f5207b7SJohn Levon static int expand_binop(struct expression *expr)
4231f5207b7SJohn Levon {
4241f5207b7SJohn Levon 	int cost;
4251f5207b7SJohn Levon 
4261f5207b7SJohn Levon 	cost = expand_expression(expr->left);
4271f5207b7SJohn Levon 	cost += expand_expression(expr->right);
4281f5207b7SJohn Levon 	if (simplify_int_binop(expr, expr->ctype))
4291f5207b7SJohn Levon 		return 0;
4301f5207b7SJohn Levon 	if (simplify_float_binop(expr))
4311f5207b7SJohn Levon 		return 0;
4321f5207b7SJohn Levon 	return cost + 1;
4331f5207b7SJohn Levon }
4341f5207b7SJohn Levon 
expand_logical(struct expression * expr)4351f5207b7SJohn Levon static int expand_logical(struct expression *expr)
4361f5207b7SJohn Levon {
4371f5207b7SJohn Levon 	struct expression *left = expr->left;
4381f5207b7SJohn Levon 	struct expression *right;
4391f5207b7SJohn Levon 	int cost, rcost;
4401f5207b7SJohn Levon 
4411f5207b7SJohn Levon 	/* Do immediate short-circuiting ... */
4421f5207b7SJohn Levon 	cost = expand_expression(left);
4431f5207b7SJohn Levon 	if (left->type == EXPR_VALUE) {
4441f5207b7SJohn Levon 		if (expr->op == SPECIAL_LOGICAL_AND) {
4451f5207b7SJohn Levon 			if (!left->value) {
4461f5207b7SJohn Levon 				expr->type = EXPR_VALUE;
4471f5207b7SJohn Levon 				expr->value = 0;
4481f5207b7SJohn Levon 				expr->taint = left->taint;
4491f5207b7SJohn Levon 				return 0;
4501f5207b7SJohn Levon 			}
4511f5207b7SJohn Levon 		} else {
4521f5207b7SJohn Levon 			if (left->value) {
4531f5207b7SJohn Levon 				expr->type = EXPR_VALUE;
4541f5207b7SJohn Levon 				expr->value = 1;
4551f5207b7SJohn Levon 				expr->taint = left->taint;
4561f5207b7SJohn Levon 				return 0;
4571f5207b7SJohn Levon 			}
4581f5207b7SJohn Levon 		}
4591f5207b7SJohn Levon 	}
4601f5207b7SJohn Levon 
4611f5207b7SJohn Levon 	right = expr->right;
4621f5207b7SJohn Levon 	rcost = expand_expression(right);
4631f5207b7SJohn Levon 	if (left->type == EXPR_VALUE && right->type == EXPR_VALUE) {
4641f5207b7SJohn Levon 		/*
4651f5207b7SJohn Levon 		 * We know the left value doesn't matter, since
4661f5207b7SJohn Levon 		 * otherwise we would have short-circuited it..
4671f5207b7SJohn Levon 		 */
4681f5207b7SJohn Levon 		expr->type = EXPR_VALUE;
4691f5207b7SJohn Levon 		expr->value = right->value != 0;
4701f5207b7SJohn Levon 		expr->taint = left->taint | right->taint;
4711f5207b7SJohn Levon 		return 0;
4721f5207b7SJohn Levon 	}
4731f5207b7SJohn Levon 
4741f5207b7SJohn Levon 	/*
4751f5207b7SJohn Levon 	 * If the right side is safe and cheaper than a branch,
4761f5207b7SJohn Levon 	 * just avoid the branch and turn it into a regular binop
4771f5207b7SJohn Levon 	 * style SAFELOGICAL.
4781f5207b7SJohn Levon 	 */
4791f5207b7SJohn Levon 	if (rcost < BRANCH_COST) {
4801f5207b7SJohn Levon 		expr->type = EXPR_BINOP;
4811f5207b7SJohn Levon 		rcost -= BRANCH_COST - 1;
4821f5207b7SJohn Levon 	}
4831f5207b7SJohn Levon 
4841f5207b7SJohn Levon 	return cost + BRANCH_COST + rcost;
4851f5207b7SJohn Levon }
4861f5207b7SJohn Levon 
expand_comma(struct expression * expr)4871f5207b7SJohn Levon static int expand_comma(struct expression *expr)
4881f5207b7SJohn Levon {
4891f5207b7SJohn Levon 	int cost;
4901f5207b7SJohn Levon 
4911f5207b7SJohn Levon 	cost = expand_expression(expr->left);
4921f5207b7SJohn Levon 	cost += expand_expression(expr->right);
4931f5207b7SJohn Levon 	if (expr->left->type == EXPR_VALUE || expr->left->type == EXPR_FVALUE) {
4941f5207b7SJohn Levon 		unsigned flags = expr->flags;
4951f5207b7SJohn Levon 		unsigned taint;
4961f5207b7SJohn Levon 		taint = expr->left->type == EXPR_VALUE ? expr->left->taint : 0;
4971f5207b7SJohn Levon 		*expr = *expr->right;
4981f5207b7SJohn Levon 		expr->flags = flags;
4991f5207b7SJohn Levon 		if (expr->type == EXPR_VALUE)
5001f5207b7SJohn Levon 			expr->taint |= Taint_comma | taint;
5011f5207b7SJohn Levon 	}
5021f5207b7SJohn Levon 	return cost;
5031f5207b7SJohn Levon }
5041f5207b7SJohn Levon 
505*c85f09ccSJohn Levon #define MOD_IGN (MOD_QUALIFIER)
5061f5207b7SJohn Levon 
compare_types(int op,struct symbol * left,struct symbol * right)5071f5207b7SJohn Levon static int compare_types(int op, struct symbol *left, struct symbol *right)
5081f5207b7SJohn Levon {
5091f5207b7SJohn Levon 	struct ctype c1 = {.base_type = left};
5101f5207b7SJohn Levon 	struct ctype c2 = {.base_type = right};
5111f5207b7SJohn Levon 	switch (op) {
5121f5207b7SJohn Levon 	case SPECIAL_EQUAL:
5131f5207b7SJohn Levon 		return !type_difference(&c1, &c2, MOD_IGN, MOD_IGN);
5141f5207b7SJohn Levon 	case SPECIAL_NOTEQUAL:
5151f5207b7SJohn Levon 		return type_difference(&c1, &c2, MOD_IGN, MOD_IGN) != NULL;
5161f5207b7SJohn Levon 	case '<':
5171f5207b7SJohn Levon 		return left->bit_size < right->bit_size;
5181f5207b7SJohn Levon 	case '>':
5191f5207b7SJohn Levon 		return left->bit_size > right->bit_size;
5201f5207b7SJohn Levon 	case SPECIAL_LTE:
5211f5207b7SJohn Levon 		return left->bit_size <= right->bit_size;
5221f5207b7SJohn Levon 	case SPECIAL_GTE:
5231f5207b7SJohn Levon 		return left->bit_size >= right->bit_size;
5241f5207b7SJohn Levon 	}
5251f5207b7SJohn Levon 	return 0;
5261f5207b7SJohn Levon }
5271f5207b7SJohn Levon 
expand_compare(struct expression * expr)5281f5207b7SJohn Levon static int expand_compare(struct expression *expr)
5291f5207b7SJohn Levon {
5301f5207b7SJohn Levon 	struct expression *left = expr->left, *right = expr->right;
5311f5207b7SJohn Levon 	int cost;
5321f5207b7SJohn Levon 
5331f5207b7SJohn Levon 	cost = expand_expression(left);
5341f5207b7SJohn Levon 	cost += expand_expression(right);
5351f5207b7SJohn Levon 
5361f5207b7SJohn Levon 	if (left && right) {
5371f5207b7SJohn Levon 		/* Type comparison? */
5381f5207b7SJohn Levon 		if (left->type == EXPR_TYPE && right->type == EXPR_TYPE) {
5391f5207b7SJohn Levon 			int op = expr->op;
5401f5207b7SJohn Levon 			expr->type = EXPR_VALUE;
5411f5207b7SJohn Levon 			expr->value = compare_types(op, left->symbol, right->symbol);
5421f5207b7SJohn Levon 			expr->taint = 0;
5431f5207b7SJohn Levon 			return 0;
5441f5207b7SJohn Levon 		}
5451f5207b7SJohn Levon 		if (simplify_cmp_binop(expr, left->ctype))
5461f5207b7SJohn Levon 			return 0;
5471f5207b7SJohn Levon 		if (simplify_float_cmp(expr, left->ctype))
5481f5207b7SJohn Levon 			return 0;
5491f5207b7SJohn Levon 	}
5501f5207b7SJohn Levon 	return cost + 1;
5511f5207b7SJohn Levon }
5521f5207b7SJohn Levon 
expand_conditional(struct expression * expr)5531f5207b7SJohn Levon static int expand_conditional(struct expression *expr)
5541f5207b7SJohn Levon {
5551f5207b7SJohn Levon 	struct expression *cond = expr->conditional;
556*c85f09ccSJohn Levon 	struct expression *valt = expr->cond_true;
557*c85f09ccSJohn Levon 	struct expression *valf = expr->cond_false;
5581f5207b7SJohn Levon 	int cost, cond_cost;
5591f5207b7SJohn Levon 
5601f5207b7SJohn Levon 	cond_cost = expand_expression(cond);
5611f5207b7SJohn Levon 	if (cond->type == EXPR_VALUE) {
5621f5207b7SJohn Levon 		unsigned flags = expr->flags;
5631f5207b7SJohn Levon 		if (!cond->value)
564*c85f09ccSJohn Levon 			valt = valf;
565*c85f09ccSJohn Levon 		if (!valt)
566*c85f09ccSJohn Levon 			valt = cond;
567*c85f09ccSJohn Levon 		cost = expand_expression(valt);
568*c85f09ccSJohn Levon 		*expr = *valt;
5691f5207b7SJohn Levon 		expr->flags = flags;
5701f5207b7SJohn Levon 		if (expr->type == EXPR_VALUE)
5711f5207b7SJohn Levon 			expr->taint |= cond->taint;
5721f5207b7SJohn Levon 		return cost;
5731f5207b7SJohn Levon 	}
5741f5207b7SJohn Levon 
575*c85f09ccSJohn Levon 	cost = expand_expression(valt);
576*c85f09ccSJohn Levon 	cost += expand_expression(valf);
5771f5207b7SJohn Levon 
5781f5207b7SJohn Levon 	if (cost < SELECT_COST) {
5791f5207b7SJohn Levon 		expr->type = EXPR_SELECT;
5801f5207b7SJohn Levon 		cost -= BRANCH_COST - 1;
5811f5207b7SJohn Levon 	}
5821f5207b7SJohn Levon 
5831f5207b7SJohn Levon 	return cost + cond_cost + BRANCH_COST;
5841f5207b7SJohn Levon }
585*c85f09ccSJohn Levon 
check_assignment(struct expression * expr)586*c85f09ccSJohn Levon static void check_assignment(struct expression *expr)
587*c85f09ccSJohn Levon {
588*c85f09ccSJohn Levon 	struct expression *right;
589*c85f09ccSJohn Levon 
590*c85f09ccSJohn Levon 	switch (expr->op) {
591*c85f09ccSJohn Levon 	case SPECIAL_SHL_ASSIGN:
592*c85f09ccSJohn Levon 	case SPECIAL_SHR_ASSIGN:
593*c85f09ccSJohn Levon 		right = expr->right;
594*c85f09ccSJohn Levon 		if (right->type != EXPR_VALUE)
595*c85f09ccSJohn Levon 			break;
596*c85f09ccSJohn Levon 		check_shift_count(expr, right);
597*c85f09ccSJohn Levon 		break;
598*c85f09ccSJohn Levon 	}
599*c85f09ccSJohn Levon 	return;
600*c85f09ccSJohn Levon }
601*c85f09ccSJohn Levon 
expand_assignment(struct expression * expr)6021f5207b7SJohn Levon static int expand_assignment(struct expression *expr)
6031f5207b7SJohn Levon {
6041f5207b7SJohn Levon 	expand_expression(expr->left);
6051f5207b7SJohn Levon 	expand_expression(expr->right);
606*c85f09ccSJohn Levon 
607*c85f09ccSJohn Levon 	if (!conservative)
608*c85f09ccSJohn Levon 		check_assignment(expr);
6091f5207b7SJohn Levon 	return SIDE_EFFECTS;
6101f5207b7SJohn Levon }
6111f5207b7SJohn Levon 
expand_addressof(struct expression * expr)6121f5207b7SJohn Levon static int expand_addressof(struct expression *expr)
6131f5207b7SJohn Levon {
6141f5207b7SJohn Levon 	return expand_expression(expr->unop);
6151f5207b7SJohn Levon }
6161f5207b7SJohn Levon 
6171f5207b7SJohn Levon /*
6181f5207b7SJohn Levon  * Look up a trustable initializer value at the requested offset.
6191f5207b7SJohn Levon  *
6201f5207b7SJohn Levon  * Return NULL if no such value can be found or statically trusted.
6211f5207b7SJohn Levon  *
6221f5207b7SJohn Levon  * FIXME!! We should check that the size is right!
6231f5207b7SJohn Levon  */
constant_symbol_value(struct symbol * sym,int offset)6241f5207b7SJohn Levon static struct expression *constant_symbol_value(struct symbol *sym, int offset)
6251f5207b7SJohn Levon {
6261f5207b7SJohn Levon 	struct expression *value;
6271f5207b7SJohn Levon 
628*c85f09ccSJohn Levon 	if (sym->ctype.modifiers & MOD_ACCESS)
6291f5207b7SJohn Levon 		return NULL;
6301f5207b7SJohn Levon 	value = sym->initializer;
6311f5207b7SJohn Levon 	if (!value)
6321f5207b7SJohn Levon 		return NULL;
6331f5207b7SJohn Levon 	if (value->type == EXPR_INITIALIZER) {
6341f5207b7SJohn Levon 		struct expression *entry;
6351f5207b7SJohn Levon 		FOR_EACH_PTR(value->expr_list, entry) {
6361f5207b7SJohn Levon 			if (entry->type != EXPR_POS) {
6371f5207b7SJohn Levon 				if (offset)
6381f5207b7SJohn Levon 					continue;
6391f5207b7SJohn Levon 				return entry;
6401f5207b7SJohn Levon 			}
6411f5207b7SJohn Levon 			if (entry->init_offset < offset)
6421f5207b7SJohn Levon 				continue;
6431f5207b7SJohn Levon 			if (entry->init_offset > offset)
6441f5207b7SJohn Levon 				return NULL;
6451f5207b7SJohn Levon 			return entry->init_expr;
6461f5207b7SJohn Levon 		} END_FOR_EACH_PTR(entry);
6471f5207b7SJohn Levon 		return NULL;
6481f5207b7SJohn Levon 	}
6491f5207b7SJohn Levon 	return value;
6501f5207b7SJohn Levon }
6511f5207b7SJohn Levon 
expand_dereference(struct expression * expr)6521f5207b7SJohn Levon static int expand_dereference(struct expression *expr)
6531f5207b7SJohn Levon {
6541f5207b7SJohn Levon 	struct expression *unop = expr->unop;
6551f5207b7SJohn Levon 	unsigned int offset;
6561f5207b7SJohn Levon 
6571f5207b7SJohn Levon 	expand_expression(unop);
6581f5207b7SJohn Levon 
6591f5207b7SJohn Levon 	/*
6601f5207b7SJohn Levon 	 * NOTE! We get a bogus warning right now for some special
6611f5207b7SJohn Levon 	 * cases: apparently I've screwed up the optimization of
6621f5207b7SJohn Levon 	 * a zero-offset dereference, and the ctype is wrong.
6631f5207b7SJohn Levon 	 *
6641f5207b7SJohn Levon 	 * Leave the warning in anyway, since this is also a good
6651f5207b7SJohn Levon 	 * test for me to get the type evaluation right..
6661f5207b7SJohn Levon 	 */
6671f5207b7SJohn Levon 	if (expr->ctype->ctype.modifiers & MOD_NODEREF)
6681f5207b7SJohn Levon 		warning(unop->pos, "dereference of noderef expression");
6691f5207b7SJohn Levon 
6701f5207b7SJohn Levon 	/*
6711f5207b7SJohn Levon 	 * Is it "symbol" or "symbol + offset"?
6721f5207b7SJohn Levon 	 */
6731f5207b7SJohn Levon 	offset = 0;
6741f5207b7SJohn Levon 	if (unop->type == EXPR_BINOP && unop->op == '+') {
6751f5207b7SJohn Levon 		struct expression *right = unop->right;
6761f5207b7SJohn Levon 		if (right->type == EXPR_VALUE) {
6771f5207b7SJohn Levon 			offset = right->value;
6781f5207b7SJohn Levon 			unop = unop->left;
6791f5207b7SJohn Levon 		}
6801f5207b7SJohn Levon 	}
6811f5207b7SJohn Levon 
6821f5207b7SJohn Levon 	if (unop->type == EXPR_SYMBOL) {
6831f5207b7SJohn Levon 		struct symbol *sym = unop->symbol;
6841f5207b7SJohn Levon 		struct expression *value = constant_symbol_value(sym, offset);
6851f5207b7SJohn Levon 
6861f5207b7SJohn Levon 		/* Const symbol with a constant initializer? */
6871f5207b7SJohn Levon 		if (value) {
6881f5207b7SJohn Levon 			/* FIXME! We should check that the size is right! */
6891f5207b7SJohn Levon 			if (value->type == EXPR_VALUE) {
690*c85f09ccSJohn Levon 				if (is_bitfield_type(value->ctype))
691*c85f09ccSJohn Levon 					return UNSAFE;
6921f5207b7SJohn Levon 				expr->type = EXPR_VALUE;
6931f5207b7SJohn Levon 				expr->value = value->value;
6941f5207b7SJohn Levon 				expr->taint = 0;
6951f5207b7SJohn Levon 				return 0;
6961f5207b7SJohn Levon 			} else if (value->type == EXPR_FVALUE) {
6971f5207b7SJohn Levon 				expr->type = EXPR_FVALUE;
6981f5207b7SJohn Levon 				expr->fvalue = value->fvalue;
6991f5207b7SJohn Levon 				return 0;
7001f5207b7SJohn Levon 			}
7011f5207b7SJohn Levon 		}
7021f5207b7SJohn Levon 
7031f5207b7SJohn Levon 		/* Direct symbol dereference? Cheap and safe */
7041f5207b7SJohn Levon 		return (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN)) ? 2 : 1;
7051f5207b7SJohn Levon 	}
7061f5207b7SJohn Levon 
7071f5207b7SJohn Levon 	return UNSAFE;
7081f5207b7SJohn Levon }
7091f5207b7SJohn Levon 
simplify_preop(struct expression * expr)7101f5207b7SJohn Levon static int simplify_preop(struct expression *expr)
7111f5207b7SJohn Levon {
7121f5207b7SJohn Levon 	struct expression *op = expr->unop;
7131f5207b7SJohn Levon 	unsigned long long v, mask;
7141f5207b7SJohn Levon 
7151f5207b7SJohn Levon 	if (op->type != EXPR_VALUE)
7161f5207b7SJohn Levon 		return 0;
7171f5207b7SJohn Levon 
7181f5207b7SJohn Levon 	mask = 1ULL << (expr->ctype->bit_size-1);
7191f5207b7SJohn Levon 	v = op->value;
7201f5207b7SJohn Levon 	switch (expr->op) {
7211f5207b7SJohn Levon 	case '+': break;
7221f5207b7SJohn Levon 	case '-':
7231f5207b7SJohn Levon 		if (v == mask && !(expr->ctype->ctype.modifiers & MOD_UNSIGNED))
7241f5207b7SJohn Levon 			goto Overflow;
7251f5207b7SJohn Levon 		v = -v;
7261f5207b7SJohn Levon 		break;
7271f5207b7SJohn Levon 	case '!': v = !v; break;
7281f5207b7SJohn Levon 	case '~': v = ~v; break;
7291f5207b7SJohn Levon 	default: return 0;
7301f5207b7SJohn Levon 	}
7311f5207b7SJohn Levon 	mask = mask | (mask-1);
7321f5207b7SJohn Levon 	expr->value = v & mask;
7331f5207b7SJohn Levon 	expr->type = EXPR_VALUE;
7341f5207b7SJohn Levon 	expr->taint = op->taint;
7351f5207b7SJohn Levon 	return 1;
7361f5207b7SJohn Levon 
7371f5207b7SJohn Levon Overflow:
7381f5207b7SJohn Levon 	if (!conservative)
7391f5207b7SJohn Levon 		warning(expr->pos, "constant integer operation overflow");
7401f5207b7SJohn Levon 	return 0;
7411f5207b7SJohn Levon }
7421f5207b7SJohn Levon 
simplify_float_preop(struct expression * expr)7431f5207b7SJohn Levon static int simplify_float_preop(struct expression *expr)
7441f5207b7SJohn Levon {
7451f5207b7SJohn Levon 	struct expression *op = expr->unop;
7461f5207b7SJohn Levon 	long double v;
7471f5207b7SJohn Levon 
7481f5207b7SJohn Levon 	if (op->type != EXPR_FVALUE)
7491f5207b7SJohn Levon 		return 0;
7501f5207b7SJohn Levon 	v = op->fvalue;
7511f5207b7SJohn Levon 	switch (expr->op) {
7521f5207b7SJohn Levon 	case '+': break;
7531f5207b7SJohn Levon 	case '-': v = -v; break;
7541f5207b7SJohn Levon 	default: return 0;
7551f5207b7SJohn Levon 	}
7561f5207b7SJohn Levon 	expr->fvalue = v;
7571f5207b7SJohn Levon 	expr->type = EXPR_FVALUE;
7581f5207b7SJohn Levon 	return 1;
7591f5207b7SJohn Levon }
7601f5207b7SJohn Levon 
7611f5207b7SJohn Levon /*
7621f5207b7SJohn Levon  * Unary post-ops: x++ and x--
7631f5207b7SJohn Levon  */
expand_postop(struct expression * expr)7641f5207b7SJohn Levon static int expand_postop(struct expression *expr)
7651f5207b7SJohn Levon {
7661f5207b7SJohn Levon 	expand_expression(expr->unop);
7671f5207b7SJohn Levon 	return SIDE_EFFECTS;
7681f5207b7SJohn Levon }
7691f5207b7SJohn Levon 
expand_preop(struct expression * expr)7701f5207b7SJohn Levon static int expand_preop(struct expression *expr)
7711f5207b7SJohn Levon {
7721f5207b7SJohn Levon 	int cost;
7731f5207b7SJohn Levon 
7741f5207b7SJohn Levon 	switch (expr->op) {
7751f5207b7SJohn Levon 	case '*':
7761f5207b7SJohn Levon 		return expand_dereference(expr);
7771f5207b7SJohn Levon 
7781f5207b7SJohn Levon 	case '&':
7791f5207b7SJohn Levon 		return expand_addressof(expr);
7801f5207b7SJohn Levon 
7811f5207b7SJohn Levon 	case SPECIAL_INCREMENT:
7821f5207b7SJohn Levon 	case SPECIAL_DECREMENT:
7831f5207b7SJohn Levon 		/*
7841f5207b7SJohn Levon 		 * From a type evaluation standpoint the preops are
7851f5207b7SJohn Levon 		 * the same as the postops
7861f5207b7SJohn Levon 		 */
7871f5207b7SJohn Levon 		return expand_postop(expr);
7881f5207b7SJohn Levon 
7891f5207b7SJohn Levon 	default:
7901f5207b7SJohn Levon 		break;
7911f5207b7SJohn Levon 	}
7921f5207b7SJohn Levon 	cost = expand_expression(expr->unop);
7931f5207b7SJohn Levon 
7941f5207b7SJohn Levon 	if (simplify_preop(expr))
7951f5207b7SJohn Levon 		return 0;
7961f5207b7SJohn Levon 	if (simplify_float_preop(expr))
7971f5207b7SJohn Levon 		return 0;
7981f5207b7SJohn Levon 	return cost + 1;
7991f5207b7SJohn Levon }
8001f5207b7SJohn Levon 
expand_arguments(struct expression_list * head)8011f5207b7SJohn Levon static int expand_arguments(struct expression_list *head)
8021f5207b7SJohn Levon {
8031f5207b7SJohn Levon 	int cost = 0;
8041f5207b7SJohn Levon 	struct expression *expr;
8051f5207b7SJohn Levon 
8061f5207b7SJohn Levon 	FOR_EACH_PTR (head, expr) {
8071f5207b7SJohn Levon 		cost += expand_expression(expr);
8081f5207b7SJohn Levon 	} END_FOR_EACH_PTR(expr);
8091f5207b7SJohn Levon 	return cost;
8101f5207b7SJohn Levon }
8111f5207b7SJohn Levon 
expand_cast(struct expression * expr)8121f5207b7SJohn Levon static int expand_cast(struct expression *expr)
8131f5207b7SJohn Levon {
8141f5207b7SJohn Levon 	int cost;
8151f5207b7SJohn Levon 	struct expression *target = expr->cast_expression;
8161f5207b7SJohn Levon 
8171f5207b7SJohn Levon 	cost = expand_expression(target);
8181f5207b7SJohn Levon 
8191f5207b7SJohn Levon 	/* Simplify normal integer casts.. */
8201f5207b7SJohn Levon 	if (target->type == EXPR_VALUE || target->type == EXPR_FVALUE) {
8211f5207b7SJohn Levon 		cast_value(expr, expr->ctype, target, target->ctype);
8221f5207b7SJohn Levon 		return 0;
8231f5207b7SJohn Levon 	}
8241f5207b7SJohn Levon 	return cost + 1;
8251f5207b7SJohn Levon }
8261f5207b7SJohn Levon 
8271f5207b7SJohn Levon /*
8281f5207b7SJohn Levon  * expand a call expression with a symbol. This
8291f5207b7SJohn Levon  * should expand builtins.
8301f5207b7SJohn Levon  */
expand_symbol_call(struct expression * expr,int cost)8311f5207b7SJohn Levon static int expand_symbol_call(struct expression *expr, int cost)
8321f5207b7SJohn Levon {
8331f5207b7SJohn Levon 	struct expression *fn = expr->fn;
8341f5207b7SJohn Levon 	struct symbol *ctype = fn->ctype;
8351f5207b7SJohn Levon 
836*c85f09ccSJohn Levon 	expand_expression(fn);
837*c85f09ccSJohn Levon 
8381f5207b7SJohn Levon 	if (fn->type != EXPR_PREOP)
8391f5207b7SJohn Levon 		return SIDE_EFFECTS;
8401f5207b7SJohn Levon 
8411f5207b7SJohn Levon 	if (ctype->op && ctype->op->expand)
8421f5207b7SJohn Levon 		return ctype->op->expand(expr, cost);
8431f5207b7SJohn Levon 
8441f5207b7SJohn Levon 	if (ctype->ctype.modifiers & MOD_PURE)
8451f5207b7SJohn Levon 		return cost + 1;
8461f5207b7SJohn Levon 
8471f5207b7SJohn Levon 	return SIDE_EFFECTS;
8481f5207b7SJohn Levon }
8491f5207b7SJohn Levon 
expand_call(struct expression * expr)8501f5207b7SJohn Levon static int expand_call(struct expression *expr)
8511f5207b7SJohn Levon {
8521f5207b7SJohn Levon 	int cost;
8531f5207b7SJohn Levon 	struct symbol *sym;
8541f5207b7SJohn Levon 	struct expression *fn = expr->fn;
8551f5207b7SJohn Levon 
8561f5207b7SJohn Levon 	cost = expand_arguments(expr->args);
8571f5207b7SJohn Levon 	sym = fn->ctype;
8581f5207b7SJohn Levon 	if (!sym) {
8591f5207b7SJohn Levon 		expression_error(expr, "function has no type");
8601f5207b7SJohn Levon 		return SIDE_EFFECTS;
8611f5207b7SJohn Levon 	}
8621f5207b7SJohn Levon 	if (sym->type == SYM_NODE)
8631f5207b7SJohn Levon 		return expand_symbol_call(expr, cost);
8641f5207b7SJohn Levon 
8651f5207b7SJohn Levon 	return SIDE_EFFECTS;
8661f5207b7SJohn Levon }
8671f5207b7SJohn Levon 
expand_expression_list(struct expression_list * list)8681f5207b7SJohn Levon static int expand_expression_list(struct expression_list *list)
8691f5207b7SJohn Levon {
8701f5207b7SJohn Levon 	int cost = 0;
8711f5207b7SJohn Levon 	struct expression *expr;
8721f5207b7SJohn Levon 
8731f5207b7SJohn Levon 	FOR_EACH_PTR(list, expr) {
8741f5207b7SJohn Levon 		cost += expand_expression(expr);
8751f5207b7SJohn Levon 	} END_FOR_EACH_PTR(expr);
8761f5207b7SJohn Levon 	return cost;
8771f5207b7SJohn Levon }
8781f5207b7SJohn Levon 
8791f5207b7SJohn Levon /*
8801f5207b7SJohn Levon  * We can simplify nested position expressions if
8811f5207b7SJohn Levon  * this is a simple (single) positional expression.
8821f5207b7SJohn Levon  */
expand_pos_expression(struct expression * expr)8831f5207b7SJohn Levon static int expand_pos_expression(struct expression *expr)
8841f5207b7SJohn Levon {
8851f5207b7SJohn Levon 	struct expression *nested = expr->init_expr;
8861f5207b7SJohn Levon 	unsigned long offset = expr->init_offset;
8871f5207b7SJohn Levon 	int nr = expr->init_nr;
8881f5207b7SJohn Levon 
8891f5207b7SJohn Levon 	if (nr == 1) {
8901f5207b7SJohn Levon 		switch (nested->type) {
8911f5207b7SJohn Levon 		case EXPR_POS:
8921f5207b7SJohn Levon 			offset += nested->init_offset;
8931f5207b7SJohn Levon 			*expr = *nested;
8941f5207b7SJohn Levon 			expr->init_offset = offset;
8951f5207b7SJohn Levon 			nested = expr;
8961f5207b7SJohn Levon 			break;
8971f5207b7SJohn Levon 
8981f5207b7SJohn Levon 		case EXPR_INITIALIZER: {
8991f5207b7SJohn Levon 			struct expression *reuse = nested, *entry;
9001f5207b7SJohn Levon 			*expr = *nested;
9011f5207b7SJohn Levon 			FOR_EACH_PTR(expr->expr_list, entry) {
9021f5207b7SJohn Levon 				if (entry->type == EXPR_POS) {
9031f5207b7SJohn Levon 					entry->init_offset += offset;
9041f5207b7SJohn Levon 				} else {
9051f5207b7SJohn Levon 					if (!reuse) {
9061f5207b7SJohn Levon 						/*
9071f5207b7SJohn Levon 						 * This happens rarely, but it can happen
9081f5207b7SJohn Levon 						 * with bitfields that are all at offset
9091f5207b7SJohn Levon 						 * zero..
9101f5207b7SJohn Levon 						 */
9111f5207b7SJohn Levon 						reuse = alloc_expression(entry->pos, EXPR_POS);
9121f5207b7SJohn Levon 					}
9131f5207b7SJohn Levon 					reuse->type = EXPR_POS;
9141f5207b7SJohn Levon 					reuse->ctype = entry->ctype;
9151f5207b7SJohn Levon 					reuse->init_offset = offset;
9161f5207b7SJohn Levon 					reuse->init_nr = 1;
9171f5207b7SJohn Levon 					reuse->init_expr = entry;
9181f5207b7SJohn Levon 					REPLACE_CURRENT_PTR(entry, reuse);
9191f5207b7SJohn Levon 					reuse = NULL;
9201f5207b7SJohn Levon 				}
9211f5207b7SJohn Levon 			} END_FOR_EACH_PTR(entry);
9221f5207b7SJohn Levon 			nested = expr;
9231f5207b7SJohn Levon 			break;
9241f5207b7SJohn Levon 		}
9251f5207b7SJohn Levon 
9261f5207b7SJohn Levon 		default:
9271f5207b7SJohn Levon 			break;
9281f5207b7SJohn Levon 		}
9291f5207b7SJohn Levon 	}
9301f5207b7SJohn Levon 	return expand_expression(nested);
9311f5207b7SJohn Levon }
9321f5207b7SJohn Levon 
bit_offset(const struct expression * expr)9331f5207b7SJohn Levon static unsigned long bit_offset(const struct expression *expr)
9341f5207b7SJohn Levon {
9351f5207b7SJohn Levon 	unsigned long offset = 0;
9361f5207b7SJohn Levon 	while (expr->type == EXPR_POS) {
9371f5207b7SJohn Levon 		offset += bytes_to_bits(expr->init_offset);
9381f5207b7SJohn Levon 		expr = expr->init_expr;
9391f5207b7SJohn Levon 	}
9401f5207b7SJohn Levon 	if (expr && expr->ctype)
9411f5207b7SJohn Levon 		offset += expr->ctype->bit_offset;
9421f5207b7SJohn Levon 	return offset;
9431f5207b7SJohn Levon }
9441f5207b7SJohn Levon 
bit_range(const struct expression * expr)9451f5207b7SJohn Levon static unsigned long bit_range(const struct expression *expr)
9461f5207b7SJohn Levon {
9471f5207b7SJohn Levon 	unsigned long range = 0;
9481f5207b7SJohn Levon 	unsigned long size = 0;
9491f5207b7SJohn Levon 	while (expr->type == EXPR_POS) {
9501f5207b7SJohn Levon 		unsigned long nr = expr->init_nr;
9511f5207b7SJohn Levon 		size = expr->ctype->bit_size;
9521f5207b7SJohn Levon 		range += (nr - 1) * size;
9531f5207b7SJohn Levon 		expr = expr->init_expr;
9541f5207b7SJohn Levon 	}
9551f5207b7SJohn Levon 	range += size;
9561f5207b7SJohn Levon 	return range;
9571f5207b7SJohn Levon }
9581f5207b7SJohn Levon 
compare_expressions(const void * _a,const void * _b)9591f5207b7SJohn Levon static int compare_expressions(const void *_a, const void *_b)
9601f5207b7SJohn Levon {
9611f5207b7SJohn Levon 	const struct expression *a = _a;
9621f5207b7SJohn Levon 	const struct expression *b = _b;
9631f5207b7SJohn Levon 	unsigned long a_pos = bit_offset(a);
9641f5207b7SJohn Levon 	unsigned long b_pos = bit_offset(b);
9651f5207b7SJohn Levon 
9661f5207b7SJohn Levon 	return (a_pos < b_pos) ? -1 : (a_pos == b_pos) ? 0 : 1;
9671f5207b7SJohn Levon }
9681f5207b7SJohn Levon 
sort_expression_list(struct expression_list ** list)9691f5207b7SJohn Levon static void sort_expression_list(struct expression_list **list)
9701f5207b7SJohn Levon {
9711f5207b7SJohn Levon 	sort_list((struct ptr_list **)list, compare_expressions);
9721f5207b7SJohn Levon }
9731f5207b7SJohn Levon 
verify_nonoverlapping(struct expression_list ** list,struct expression * expr)9741f5207b7SJohn Levon static void verify_nonoverlapping(struct expression_list **list, struct expression *expr)
9751f5207b7SJohn Levon {
9761f5207b7SJohn Levon 	struct expression *a = NULL;
9771f5207b7SJohn Levon 	unsigned long max = 0;
9781f5207b7SJohn Levon 	unsigned long whole = expr->ctype->bit_size;
9791f5207b7SJohn Levon 	struct expression *b;
9801f5207b7SJohn Levon 
9811f5207b7SJohn Levon 	if (!Woverride_init)
9821f5207b7SJohn Levon 		return;
9831f5207b7SJohn Levon 
9841f5207b7SJohn Levon 	FOR_EACH_PTR(*list, b) {
9851f5207b7SJohn Levon 		unsigned long off, end;
9861f5207b7SJohn Levon 		if (!b->ctype || !b->ctype->bit_size)
9871f5207b7SJohn Levon 			continue;
9881f5207b7SJohn Levon 		off = bit_offset(b);
9891f5207b7SJohn Levon 		if (a && off < max) {
9901f5207b7SJohn Levon 			warning(a->pos, "Initializer entry defined twice");
9911f5207b7SJohn Levon 			info(b->pos, "  also defined here");
9921f5207b7SJohn Levon 			if (!Woverride_init_all)
9931f5207b7SJohn Levon 				return;
9941f5207b7SJohn Levon 		}
9951f5207b7SJohn Levon 		end = off + bit_range(b);
9961f5207b7SJohn Levon 		if (!a && !Woverride_init_whole_range) {
9971f5207b7SJohn Levon 			// If first entry is the whole range, do not let
9981f5207b7SJohn Levon 			// any warning about it (this allow to initialize
9991f5207b7SJohn Levon 			// an array with some default value and then override
10001f5207b7SJohn Levon 			// some specific entries).
10011f5207b7SJohn Levon 			if (off == 0 && end == whole)
10021f5207b7SJohn Levon 				continue;
10031f5207b7SJohn Levon 		}
10041f5207b7SJohn Levon 		if (end > max) {
10051f5207b7SJohn Levon 			max = end;
10061f5207b7SJohn Levon 			a = b;
10071f5207b7SJohn Levon 		}
10081f5207b7SJohn Levon 	} END_FOR_EACH_PTR(b);
10091f5207b7SJohn Levon }
10101f5207b7SJohn Levon 
expand_expression(struct expression * expr)10111f5207b7SJohn Levon static int expand_expression(struct expression *expr)
10121f5207b7SJohn Levon {
10131f5207b7SJohn Levon 	if (!expr)
10141f5207b7SJohn Levon 		return 0;
10151f5207b7SJohn Levon 	if (!expr->ctype || expr->ctype == &bad_ctype)
10161f5207b7SJohn Levon 		return UNSAFE;
10171f5207b7SJohn Levon 
10181f5207b7SJohn Levon 	switch (expr->type) {
10191f5207b7SJohn Levon 	case EXPR_VALUE:
10201f5207b7SJohn Levon 	case EXPR_FVALUE:
10211f5207b7SJohn Levon 	case EXPR_STRING:
10221f5207b7SJohn Levon 		return 0;
10231f5207b7SJohn Levon 	case EXPR_TYPE:
10241f5207b7SJohn Levon 	case EXPR_SYMBOL:
10251f5207b7SJohn Levon 		return expand_symbol_expression(expr);
10261f5207b7SJohn Levon 	case EXPR_BINOP:
10271f5207b7SJohn Levon 		return expand_binop(expr);
10281f5207b7SJohn Levon 
10291f5207b7SJohn Levon 	case EXPR_LOGICAL:
10301f5207b7SJohn Levon 		return expand_logical(expr);
10311f5207b7SJohn Levon 
10321f5207b7SJohn Levon 	case EXPR_COMMA:
10331f5207b7SJohn Levon 		return expand_comma(expr);
10341f5207b7SJohn Levon 
10351f5207b7SJohn Levon 	case EXPR_COMPARE:
10361f5207b7SJohn Levon 		return expand_compare(expr);
10371f5207b7SJohn Levon 
10381f5207b7SJohn Levon 	case EXPR_ASSIGNMENT:
10391f5207b7SJohn Levon 		return expand_assignment(expr);
10401f5207b7SJohn Levon 
10411f5207b7SJohn Levon 	case EXPR_PREOP:
10421f5207b7SJohn Levon 		return expand_preop(expr);
10431f5207b7SJohn Levon 
10441f5207b7SJohn Levon 	case EXPR_POSTOP:
10451f5207b7SJohn Levon 		return expand_postop(expr);
10461f5207b7SJohn Levon 
10471f5207b7SJohn Levon 	case EXPR_CAST:
10481f5207b7SJohn Levon 	case EXPR_FORCE_CAST:
10491f5207b7SJohn Levon 	case EXPR_IMPLIED_CAST:
10501f5207b7SJohn Levon 		return expand_cast(expr);
10511f5207b7SJohn Levon 
10521f5207b7SJohn Levon 	case EXPR_CALL:
10531f5207b7SJohn Levon 		return expand_call(expr);
10541f5207b7SJohn Levon 
10551f5207b7SJohn Levon 	case EXPR_DEREF:
10561f5207b7SJohn Levon 		warning(expr->pos, "we should not have an EXPR_DEREF left at expansion time");
10571f5207b7SJohn Levon 		return UNSAFE;
10581f5207b7SJohn Levon 
10591f5207b7SJohn Levon 	case EXPR_SELECT:
10601f5207b7SJohn Levon 	case EXPR_CONDITIONAL:
10611f5207b7SJohn Levon 		return expand_conditional(expr);
10621f5207b7SJohn Levon 
10631f5207b7SJohn Levon 	case EXPR_STATEMENT: {
10641f5207b7SJohn Levon 		struct statement *stmt = expr->statement;
10651f5207b7SJohn Levon 		int cost = expand_statement(stmt);
10661f5207b7SJohn Levon 
10671f5207b7SJohn Levon 		if (stmt->type == STMT_EXPRESSION && stmt->expression)
10681f5207b7SJohn Levon 			*expr = *stmt->expression;
10691f5207b7SJohn Levon 		return cost;
10701f5207b7SJohn Levon 	}
10711f5207b7SJohn Levon 
10721f5207b7SJohn Levon 	case EXPR_LABEL:
10731f5207b7SJohn Levon 		return 0;
10741f5207b7SJohn Levon 
10751f5207b7SJohn Levon 	case EXPR_INITIALIZER:
10761f5207b7SJohn Levon 		sort_expression_list(&expr->expr_list);
10771f5207b7SJohn Levon 		verify_nonoverlapping(&expr->expr_list, expr);
10781f5207b7SJohn Levon 		return expand_expression_list(expr->expr_list);
10791f5207b7SJohn Levon 
10801f5207b7SJohn Levon 	case EXPR_IDENTIFIER:
10811f5207b7SJohn Levon 		return UNSAFE;
10821f5207b7SJohn Levon 
10831f5207b7SJohn Levon 	case EXPR_INDEX:
10841f5207b7SJohn Levon 		return UNSAFE;
10851f5207b7SJohn Levon 
10861f5207b7SJohn Levon 	case EXPR_SLICE:
10871f5207b7SJohn Levon 		return expand_expression(expr->base) + 1;
10881f5207b7SJohn Levon 
10891f5207b7SJohn Levon 	case EXPR_POS:
10901f5207b7SJohn Levon 		return expand_pos_expression(expr);
10911f5207b7SJohn Levon 
10921f5207b7SJohn Levon 	case EXPR_SIZEOF:
10931f5207b7SJohn Levon 	case EXPR_PTRSIZEOF:
10941f5207b7SJohn Levon 	case EXPR_ALIGNOF:
10951f5207b7SJohn Levon 	case EXPR_OFFSETOF:
10961f5207b7SJohn Levon 		expression_error(expr, "internal front-end error: sizeof in expansion?");
10971f5207b7SJohn Levon 		return UNSAFE;
1098*c85f09ccSJohn Levon 	case EXPR_ASM_OPERAND:
1099*c85f09ccSJohn Levon 		expression_error(expr, "internal front-end error: ASM_OPERAND in expansion?");
1100*c85f09ccSJohn Levon 		return UNSAFE;
11011f5207b7SJohn Levon 	}
11021f5207b7SJohn Levon 	return SIDE_EFFECTS;
11031f5207b7SJohn Levon }
11041f5207b7SJohn Levon 
expand_const_expression(struct expression * expr,const char * where)11051f5207b7SJohn Levon static void expand_const_expression(struct expression *expr, const char *where)
11061f5207b7SJohn Levon {
11071f5207b7SJohn Levon 	if (expr) {
11081f5207b7SJohn Levon 		expand_expression(expr);
11091f5207b7SJohn Levon 		if (expr->type != EXPR_VALUE)
11101f5207b7SJohn Levon 			expression_error(expr, "Expected constant expression in %s", where);
11111f5207b7SJohn Levon 	}
11121f5207b7SJohn Levon }
11131f5207b7SJohn Levon 
expand_symbol(struct symbol * sym)11141f5207b7SJohn Levon int expand_symbol(struct symbol *sym)
11151f5207b7SJohn Levon {
11161f5207b7SJohn Levon 	int retval;
11171f5207b7SJohn Levon 	struct symbol *base_type;
11181f5207b7SJohn Levon 
11191f5207b7SJohn Levon 	if (!sym)
11201f5207b7SJohn Levon 		return 0;
11211f5207b7SJohn Levon 	base_type = sym->ctype.base_type;
11221f5207b7SJohn Levon 	if (!base_type)
11231f5207b7SJohn Levon 		return 0;
11241f5207b7SJohn Levon 
11251f5207b7SJohn Levon 	retval = expand_expression(sym->initializer);
11261f5207b7SJohn Levon 	/* expand the body of the symbol */
11271f5207b7SJohn Levon 	if (base_type->type == SYM_FN) {
11281f5207b7SJohn Levon 		if (base_type->stmt)
11291f5207b7SJohn Levon 			expand_statement(base_type->stmt);
11301f5207b7SJohn Levon 	}
11311f5207b7SJohn Levon 	return retval;
11321f5207b7SJohn Levon }
11331f5207b7SJohn Levon 
expand_return_expression(struct statement * stmt)11341f5207b7SJohn Levon static void expand_return_expression(struct statement *stmt)
11351f5207b7SJohn Levon {
11361f5207b7SJohn Levon 	expand_expression(stmt->expression);
11371f5207b7SJohn Levon }
11381f5207b7SJohn Levon 
expand_if_statement(struct statement * stmt)11391f5207b7SJohn Levon static int expand_if_statement(struct statement *stmt)
11401f5207b7SJohn Levon {
11411f5207b7SJohn Levon 	struct expression *expr = stmt->if_conditional;
11421f5207b7SJohn Levon 
11431f5207b7SJohn Levon 	if (!expr || !expr->ctype || expr->ctype == &bad_ctype)
11441f5207b7SJohn Levon 		return UNSAFE;
11451f5207b7SJohn Levon 
11461f5207b7SJohn Levon 	expand_expression(expr);
11471f5207b7SJohn Levon 
11481f5207b7SJohn Levon /* This is only valid if nobody jumps into the "dead" side */
11491f5207b7SJohn Levon #if 0
11501f5207b7SJohn Levon 	/* Simplify constant conditionals without even evaluating the false side */
11511f5207b7SJohn Levon 	if (expr->type == EXPR_VALUE) {
11521f5207b7SJohn Levon 		struct statement *simple;
11531f5207b7SJohn Levon 		simple = expr->value ? stmt->if_true : stmt->if_false;
11541f5207b7SJohn Levon 
11551f5207b7SJohn Levon 		/* Nothing? */
11561f5207b7SJohn Levon 		if (!simple) {
11571f5207b7SJohn Levon 			stmt->type = STMT_NONE;
11581f5207b7SJohn Levon 			return 0;
11591f5207b7SJohn Levon 		}
11601f5207b7SJohn Levon 		expand_statement(simple);
11611f5207b7SJohn Levon 		*stmt = *simple;
11621f5207b7SJohn Levon 		return SIDE_EFFECTS;
11631f5207b7SJohn Levon 	}
11641f5207b7SJohn Levon #endif
11651f5207b7SJohn Levon 	expand_statement(stmt->if_true);
11661f5207b7SJohn Levon 	expand_statement(stmt->if_false);
11671f5207b7SJohn Levon 	return SIDE_EFFECTS;
11681f5207b7SJohn Levon }
11691f5207b7SJohn Levon 
11701f5207b7SJohn Levon /*
11711f5207b7SJohn Levon  * Expanding a compound statement is really just
11721f5207b7SJohn Levon  * about adding up the costs of each individual
11731f5207b7SJohn Levon  * statement.
11741f5207b7SJohn Levon  *
11751f5207b7SJohn Levon  * We also collapse a simple compound statement:
11761f5207b7SJohn Levon  * this would trigger for simple inline functions,
11771f5207b7SJohn Levon  * except we would have to check the "return"
11781f5207b7SJohn Levon  * symbol usage. Next time.
11791f5207b7SJohn Levon  */
expand_compound(struct statement * stmt)11801f5207b7SJohn Levon static int expand_compound(struct statement *stmt)
11811f5207b7SJohn Levon {
11821f5207b7SJohn Levon 	struct statement *s, *last;
11831f5207b7SJohn Levon 	int cost, statements;
11841f5207b7SJohn Levon 
11851f5207b7SJohn Levon 	if (stmt->ret)
11861f5207b7SJohn Levon 		expand_symbol(stmt->ret);
11871f5207b7SJohn Levon 
11881f5207b7SJohn Levon 	last = stmt->args;
11891f5207b7SJohn Levon 	cost = expand_statement(last);
11901f5207b7SJohn Levon 	statements = last != NULL;
11911f5207b7SJohn Levon 	FOR_EACH_PTR(stmt->stmts, s) {
11921f5207b7SJohn Levon 		statements++;
11931f5207b7SJohn Levon 		last = s;
11941f5207b7SJohn Levon 		cost += expand_statement(s);
11951f5207b7SJohn Levon 	} END_FOR_EACH_PTR(s);
11961f5207b7SJohn Levon 
11971f5207b7SJohn Levon 	if (statements == 1 && !stmt->ret)
11981f5207b7SJohn Levon 		*stmt = *last;
11991f5207b7SJohn Levon 
12001f5207b7SJohn Levon 	return cost;
12011f5207b7SJohn Levon }
12021f5207b7SJohn Levon 
expand_statement(struct statement * stmt)12031f5207b7SJohn Levon static int expand_statement(struct statement *stmt)
12041f5207b7SJohn Levon {
12051f5207b7SJohn Levon 	if (!stmt)
12061f5207b7SJohn Levon 		return 0;
12071f5207b7SJohn Levon 
12081f5207b7SJohn Levon 	switch (stmt->type) {
12091f5207b7SJohn Levon 	case STMT_DECLARATION: {
12101f5207b7SJohn Levon 		struct symbol *sym;
12111f5207b7SJohn Levon 		FOR_EACH_PTR(stmt->declaration, sym) {
12121f5207b7SJohn Levon 			expand_symbol(sym);
12131f5207b7SJohn Levon 		} END_FOR_EACH_PTR(sym);
12141f5207b7SJohn Levon 		return SIDE_EFFECTS;
12151f5207b7SJohn Levon 	}
12161f5207b7SJohn Levon 
12171f5207b7SJohn Levon 	case STMT_RETURN:
12181f5207b7SJohn Levon 		expand_return_expression(stmt);
12191f5207b7SJohn Levon 		return SIDE_EFFECTS;
12201f5207b7SJohn Levon 
12211f5207b7SJohn Levon 	case STMT_EXPRESSION:
12221f5207b7SJohn Levon 		return expand_expression(stmt->expression);
12231f5207b7SJohn Levon 
12241f5207b7SJohn Levon 	case STMT_COMPOUND:
12251f5207b7SJohn Levon 		return expand_compound(stmt);
12261f5207b7SJohn Levon 
12271f5207b7SJohn Levon 	case STMT_IF:
12281f5207b7SJohn Levon 		return expand_if_statement(stmt);
12291f5207b7SJohn Levon 
12301f5207b7SJohn Levon 	case STMT_ITERATOR:
12311f5207b7SJohn Levon 		expand_expression(stmt->iterator_pre_condition);
12321f5207b7SJohn Levon 		expand_expression(stmt->iterator_post_condition);
12331f5207b7SJohn Levon 		expand_statement(stmt->iterator_pre_statement);
12341f5207b7SJohn Levon 		expand_statement(stmt->iterator_statement);
12351f5207b7SJohn Levon 		expand_statement(stmt->iterator_post_statement);
12361f5207b7SJohn Levon 		return SIDE_EFFECTS;
12371f5207b7SJohn Levon 
12381f5207b7SJohn Levon 	case STMT_SWITCH:
12391f5207b7SJohn Levon 		expand_expression(stmt->switch_expression);
12401f5207b7SJohn Levon 		expand_statement(stmt->switch_statement);
12411f5207b7SJohn Levon 		return SIDE_EFFECTS;
12421f5207b7SJohn Levon 
12431f5207b7SJohn Levon 	case STMT_CASE:
12441f5207b7SJohn Levon 		expand_const_expression(stmt->case_expression, "case statement");
12451f5207b7SJohn Levon 		expand_const_expression(stmt->case_to, "case statement");
12461f5207b7SJohn Levon 		expand_statement(stmt->case_statement);
12471f5207b7SJohn Levon 		return SIDE_EFFECTS;
12481f5207b7SJohn Levon 
12491f5207b7SJohn Levon 	case STMT_LABEL:
12501f5207b7SJohn Levon 		expand_statement(stmt->label_statement);
12511f5207b7SJohn Levon 		return SIDE_EFFECTS;
12521f5207b7SJohn Levon 
12531f5207b7SJohn Levon 	case STMT_GOTO:
12541f5207b7SJohn Levon 		expand_expression(stmt->goto_expression);
12551f5207b7SJohn Levon 		return SIDE_EFFECTS;
12561f5207b7SJohn Levon 
12571f5207b7SJohn Levon 	case STMT_NONE:
12581f5207b7SJohn Levon 		break;
12591f5207b7SJohn Levon 	case STMT_ASM:
12601f5207b7SJohn Levon 		/* FIXME! Do the asm parameter evaluation! */
12611f5207b7SJohn Levon 		break;
12621f5207b7SJohn Levon 	case STMT_CONTEXT:
12631f5207b7SJohn Levon 		expand_expression(stmt->expression);
12641f5207b7SJohn Levon 		break;
12651f5207b7SJohn Levon 	case STMT_RANGE:
12661f5207b7SJohn Levon 		expand_expression(stmt->range_expression);
12671f5207b7SJohn Levon 		expand_expression(stmt->range_low);
12681f5207b7SJohn Levon 		expand_expression(stmt->range_high);
12691f5207b7SJohn Levon 		break;
12701f5207b7SJohn Levon 	}
12711f5207b7SJohn Levon 	return SIDE_EFFECTS;
12721f5207b7SJohn Levon }
12731f5207b7SJohn Levon 
bad_integer_constant_expression(struct expression * expr)12741f5207b7SJohn Levon static inline int bad_integer_constant_expression(struct expression *expr)
12751f5207b7SJohn Levon {
12761f5207b7SJohn Levon 	if (!(expr->flags & CEF_ICE))
12771f5207b7SJohn Levon 		return 1;
12781f5207b7SJohn Levon 	if (expr->taint & Taint_comma)
12791f5207b7SJohn Levon 		return 1;
12801f5207b7SJohn Levon 	return 0;
12811f5207b7SJohn Levon }
12821f5207b7SJohn Levon 
__get_expression_value(struct expression * expr,int strict)12831f5207b7SJohn Levon static long long __get_expression_value(struct expression *expr, int strict)
12841f5207b7SJohn Levon {
12851f5207b7SJohn Levon 	long long value, mask;
12861f5207b7SJohn Levon 	struct symbol *ctype;
12871f5207b7SJohn Levon 
12881f5207b7SJohn Levon 	if (!expr)
12891f5207b7SJohn Levon 		return 0;
12901f5207b7SJohn Levon 	ctype = evaluate_expression(expr);
12911f5207b7SJohn Levon 	if (!ctype) {
12921f5207b7SJohn Levon 		expression_error(expr, "bad constant expression type");
12931f5207b7SJohn Levon 		return 0;
12941f5207b7SJohn Levon 	}
12951f5207b7SJohn Levon 	expand_expression(expr);
12961f5207b7SJohn Levon 	if (expr->type != EXPR_VALUE) {
12971f5207b7SJohn Levon 		if (strict != 2)
12981f5207b7SJohn Levon 			expression_error(expr, "bad constant expression");
12991f5207b7SJohn Levon 		return 0;
13001f5207b7SJohn Levon 	}
1301*c85f09ccSJohn Levon #if 0	// This complains about "1 ? 1 :__bits_per()" which the kernel use
13021f5207b7SJohn Levon 	if ((strict == 1) && bad_integer_constant_expression(expr)) {
13031f5207b7SJohn Levon 		expression_error(expr, "bad integer constant expression");
13041f5207b7SJohn Levon 		return 0;
13051f5207b7SJohn Levon 	}
1306*c85f09ccSJohn Levon #endif
13071f5207b7SJohn Levon 
13081f5207b7SJohn Levon 	value = expr->value;
13091f5207b7SJohn Levon 	mask = 1ULL << (ctype->bit_size-1);
13101f5207b7SJohn Levon 
13111f5207b7SJohn Levon 	if (value & mask) {
13121f5207b7SJohn Levon 		while (ctype->type != SYM_BASETYPE)
13131f5207b7SJohn Levon 			ctype = ctype->ctype.base_type;
13141f5207b7SJohn Levon 		if (!(ctype->ctype.modifiers & MOD_UNSIGNED))
13151f5207b7SJohn Levon 			value = value | mask | ~(mask-1);
13161f5207b7SJohn Levon 	}
13171f5207b7SJohn Levon 	return value;
13181f5207b7SJohn Levon }
13191f5207b7SJohn Levon 
get_expression_value(struct expression * expr)13201f5207b7SJohn Levon long long get_expression_value(struct expression *expr)
13211f5207b7SJohn Levon {
13221f5207b7SJohn Levon 	return __get_expression_value(expr, 0);
13231f5207b7SJohn Levon }
13241f5207b7SJohn Levon 
const_expression_value(struct expression * expr)13251f5207b7SJohn Levon long long const_expression_value(struct expression *expr)
13261f5207b7SJohn Levon {
13271f5207b7SJohn Levon 	return __get_expression_value(expr, 1);
13281f5207b7SJohn Levon }
13291f5207b7SJohn Levon 
get_expression_value_silent(struct expression * expr)13301f5207b7SJohn Levon long long get_expression_value_silent(struct expression *expr)
13311f5207b7SJohn Levon {
13321f5207b7SJohn Levon 
13331f5207b7SJohn Levon 	return __get_expression_value(expr, 2);
13341f5207b7SJohn Levon }
13351f5207b7SJohn Levon 
expr_truth_value(struct expression * expr)13361f5207b7SJohn Levon int expr_truth_value(struct expression *expr)
13371f5207b7SJohn Levon {
13381f5207b7SJohn Levon 	const int saved = conservative;
13391f5207b7SJohn Levon 	struct symbol *ctype;
13401f5207b7SJohn Levon 
13411f5207b7SJohn Levon 	if (!expr)
13421f5207b7SJohn Levon 		return 0;
13431f5207b7SJohn Levon 
13441f5207b7SJohn Levon 	ctype = evaluate_expression(expr);
13451f5207b7SJohn Levon 	if (!ctype)
13461f5207b7SJohn Levon 		return -1;
13471f5207b7SJohn Levon 
13481f5207b7SJohn Levon 	conservative = 1;
13491f5207b7SJohn Levon 	expand_expression(expr);
13501f5207b7SJohn Levon 	conservative = saved;
13511f5207b7SJohn Levon 
13521f5207b7SJohn Levon redo:
13531f5207b7SJohn Levon 	switch (expr->type) {
13541f5207b7SJohn Levon 	case EXPR_COMMA:
13551f5207b7SJohn Levon 		expr = expr->right;
13561f5207b7SJohn Levon 		goto redo;
13571f5207b7SJohn Levon 	case EXPR_VALUE:
13581f5207b7SJohn Levon 		return expr->value != 0;
13591f5207b7SJohn Levon 	case EXPR_FVALUE:
13601f5207b7SJohn Levon 		return expr->fvalue != 0;
13611f5207b7SJohn Levon 	default:
13621f5207b7SJohn Levon 		return -1;
13631f5207b7SJohn Levon 	}
13641f5207b7SJohn Levon }
13651f5207b7SJohn Levon 
is_zero_constant(struct expression * expr)13661f5207b7SJohn Levon int is_zero_constant(struct expression *expr)
13671f5207b7SJohn Levon {
13681f5207b7SJohn Levon 	const int saved = conservative;
13691f5207b7SJohn Levon 	conservative = 1;
13701f5207b7SJohn Levon 	expand_expression(expr);
13711f5207b7SJohn Levon 	conservative = saved;
13721f5207b7SJohn Levon 	return expr->type == EXPR_VALUE && !expr->value;
13731f5207b7SJohn Levon }
1374