/*
 * Copyright (C) 2010 Dan Carpenter.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
 */

#define _GNU_SOURCE
#include <string.h>

#include "symbol.h"
#include "smatch.h"
#include "smatch_slist.h"
#include "smatch_extra.h"

static bool get_rl_sval(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *sval_res);
static bool get_rl_internal(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res);
static bool handle_variable(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval);
static struct range_list *(*custom_handle_variable)(struct expression *expr);

static bool get_implied_value_internal(struct expression *expr, int *recurse_cnt, sval_t *res_sval);
static int get_absolute_rl_internal(struct expression *expr, struct range_list **rl, int *recurse_cnt);

static sval_t zero  = {.type = &int_ctype, {.value = 0} };
static sval_t one   = {.type = &int_ctype, {.value = 1} };

static int fast_math_only;

struct range_list *rl_zero(void)
{
	static struct range_list *zero_perm;

	if (!zero_perm)
		zero_perm = clone_rl_permanent(alloc_rl(zero, zero));
	return zero_perm;
}

struct range_list *rl_one(void)
{
	static struct range_list *one_perm;

	if (!one_perm)
		one_perm = clone_rl_permanent(alloc_rl(one, one));

	return one_perm;
}

enum {
	RL_EXACT,
	RL_HARD,
	RL_FUZZY,
	RL_IMPLIED,
	RL_ABSOLUTE,
	RL_REAL_ABSOLUTE,
};

static bool last_stmt_rl(struct statement *stmt, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct expression *expr;

	if (!stmt)
		return false;

	stmt = last_ptr_list((struct ptr_list *)stmt->stmts);
	if (stmt->type == STMT_LABEL) {
		if (stmt->label_statement &&
		    stmt->label_statement->type == STMT_EXPRESSION)
			expr = stmt->label_statement->expression;
		else
			return false;
	} else if (stmt->type == STMT_EXPRESSION) {
		expr = stmt->expression;
	} else {
		return false;
	}
	return get_rl_sval(expr, implied, recurse_cnt, res, res_sval);
}

static bool handle_expression_statement_rl(struct expression *expr, int implied,
		int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	return last_stmt_rl(get_expression_statement(expr), implied, recurse_cnt, res, res_sval);
}

static bool handle_address(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct range_list *rl;
	static int recursed;
	sval_t sval;

	if (recursed > 10)
		return false;
	if (implied == RL_EXACT)
		return false;

	if (custom_handle_variable) {
		rl = custom_handle_variable(expr);
		if (rl) {
			*res = rl;
			return true;
		}
	}

	recursed++;
	if (get_mtag_sval(expr, &sval)) {
		recursed--;
		*res_sval = sval;
		return true;
	}

	if (get_address_rl(expr, res)) {
		recursed--;
		return true;
	}
	recursed--;
	return 0;
}

static bool handle_ampersand_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	return handle_address(expr, implied, recurse_cnt, res, res_sval);
}

static bool handle_negate_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	if (known_condition_true(expr->unop)) {
		*res_sval = zero;
		return true;
	}
	if (known_condition_false(expr->unop)) {
		*res_sval = one;
		return true;
	}

	if (implied == RL_EXACT)
		return false;

	if (implied_condition_true(expr->unop)) {
		*res_sval = zero;
		return true;
	}
	if (implied_condition_false(expr->unop)) {
		*res_sval = one;
		return true;
	}

	*res = alloc_rl(zero, one);
	return true;
}

static bool handle_bitwise_negate(struct expression *expr, int implied, int *recurse_cnt, sval_t *res_sval)
{
	struct range_list *rl;
	sval_t sval = {};

	if (!get_rl_sval(expr->unop, implied, recurse_cnt, &rl, &sval))
		return false;
	if (!sval.type && !rl_to_sval(rl, &sval))
		return false;
	sval = sval_preop(sval, '~');
	sval_cast(get_type(expr->unop), sval);
	*res_sval = sval;
	return true;
}

static bool untrusted_type_min(struct expression *expr)
{
	struct range_list *rl;

	rl = var_user_rl(expr);
	return rl && sval_is_min(rl_min(rl));
}

static bool handle_minus_preop(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct range_list *rl;
	struct range_list *ret = NULL;
	struct symbol *type;
	sval_t neg_one = { .value = -1 };
	sval_t zero = { .value = 0 };
	sval_t sval = {};

	if (!get_rl_sval(expr->unop, implied, recurse_cnt, &rl, &sval))
		return false;
	if (sval.type) {
		*res_sval = sval_preop(sval, '-');
		return true;
	}
	/*
	 * One complication is that -INT_MIN is still INT_MIN because of integer
	 * overflows...  But how many times do we set a time out to INT_MIN?
	 * So normally when we call abs() then it does return a positive value.
	 *
	 */
	type = rl_type(rl);
	neg_one.type = zero.type = type;

	if (sval_is_negative(rl_min(rl))) {
		struct range_list *neg;
		struct data_range *drange;
		sval_t new_min, new_max;

		neg = alloc_rl(sval_type_min(type), neg_one);
		neg = rl_intersection(rl, neg);

		if (sval_is_min(rl_min(neg)) && !sval_is_min(rl_max(neg)))
			neg = remove_range(neg, sval_type_min(type), sval_type_min(type));

		FOR_EACH_PTR(neg, drange) {
			new_min = drange->max;
			new_min.value = -new_min.value;
			new_max = drange->min;
			new_max.value = -new_max.value;
			add_range(&ret, new_min, new_max);
		} END_FOR_EACH_PTR(drange);

		if (untrusted_type_min(expr))
			add_range(&ret, sval_type_min(type), sval_type_min(type));
	}

	if (!sval_is_negative(rl_max(rl))) {
		struct range_list *pos;
		struct data_range *drange;
		sval_t new_min, new_max;

		pos = alloc_rl(zero, sval_type_max(type));
		pos = rl_intersection(rl, pos);

		FOR_EACH_PTR(pos, drange) {
			new_min = drange->max;
			new_min.value = -new_min.value;
			new_max = drange->min;
			new_max.value = -new_max.value;
			add_range(&ret, new_min, new_max);
		} END_FOR_EACH_PTR(drange);
	}

	*res = ret;
	return true;
}

static bool handle_preop_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	switch (expr->op) {
	case '&':
		return handle_ampersand_rl(expr, implied, recurse_cnt, res, res_sval);
	case '!':
		return handle_negate_rl(expr, implied, recurse_cnt, res, res_sval);
	case '~':
		return handle_bitwise_negate(expr, implied, recurse_cnt, res_sval);
	case '-':
		return handle_minus_preop(expr, implied, recurse_cnt, res, res_sval);
	case '*':
		return handle_variable(expr, implied, recurse_cnt, res, res_sval);
	case '(':
		return handle_expression_statement_rl(expr, implied, recurse_cnt, res, res_sval);
	default:
		return false;
	}
}

static bool handle_divide_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
	struct range_list *left_rl = NULL;
	struct range_list *right_rl = NULL;
	struct symbol *type;

	type = get_type(expr);

	get_rl_internal(expr->left, implied, recurse_cnt, &left_rl);
	left_rl = cast_rl(type, left_rl);
	get_rl_internal(expr->right, implied, recurse_cnt, &right_rl);
	right_rl = cast_rl(type, right_rl);

	if (!left_rl || !right_rl)
		return false;

	if (implied != RL_REAL_ABSOLUTE) {
		if (is_whole_rl(left_rl) || is_whole_rl(right_rl))
			return false;
	}

	*res = rl_binop(left_rl, '/', right_rl);
	return true;
}

static int handle_offset_subtraction(struct expression *expr)
{
	struct expression *left, *right;
	struct symbol *left_sym, *right_sym;
	struct symbol *type;
	int left_offset, right_offset;

	type = get_type(expr);
	if (!type || type->type != SYM_PTR)
		return -1;
	type = get_real_base_type(type);
	if (!type || (type_bits(type) != 8 && (type != &void_ctype)))
		return -1;

	left = strip_expr(expr->left);
	right = strip_expr(expr->right);

	if (left->type != EXPR_PREOP || left->op != '&')
		return -1;
	left = strip_expr(left->unop);

	left_sym = expr_to_sym(left);
	right_sym = expr_to_sym(right);
	if (!left_sym || left_sym != right_sym)
		return -1;

	left_offset = get_member_offset_from_deref(left);
	if (right->type == EXPR_SYMBOL)
		right_offset = 0;
	else {
		if (right->type != EXPR_PREOP || right->op != '&')
			return -1;
		right = strip_expr(right->unop);
		right_offset = get_member_offset_from_deref(right);
	}
	if (left_offset < 0 || right_offset < 0)
		return -1;

	return left_offset - right_offset;
}

static bool handle_container_of(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
	struct expression *left, *right;
	struct range_list *left_orig = NULL;
	struct symbol *type;
	sval_t left_sval, right_sval;

	/*
	 * I'm not 100% if ABSOLUTE should be handled like this but I think if
	 * IMPLIED overrules ABSOLUTE so it's a moot point.
	 *
	 * What this function does is if we have:
	 * 	p = container_of(foo, struct my_struct, member);
	 * Then if the offset is non-zero we can assume that p is a valid
	 * pointer.  Mathematically, that's not necessarily true, but in
	 * pratical terms if p isn't valid then we're already in deep trouble
	 * to the point where printing more warnings now won't help.
	 *
	 * There are places were the author knows that container_of() is a
	 * no-op so the code will do a NULL test on the result.  (This is
	 * obviously horrible code).  So to handle code like this if the offset
	 * is zero then the result can be NULL.
	 */
	if (implied != RL_IMPLIED &&
	    implied != RL_ABSOLUTE &&
	    implied != RL_REAL_ABSOLUTE)
		return false;

	type = get_type(expr);
	if (!type || type->type != SYM_PTR)
		return false;
	type = get_real_base_type(type);
	if (!type || (type_bits(type) != 8 && (type != &void_ctype)))
		return false;

	left = strip_expr(expr->left);
	right = strip_expr(expr->right);

	if (right->type != EXPR_OFFSETOF)
		return false;

	if (!get_value(right, &right_sval))
		return false;
	/* Handle offset == 0 in the caller if possible. */
	if (right_sval.value == 0)
		return false;

	get_rl_internal(left, implied, recurse_cnt, &left_orig);
	/*
	 * I think known binops are already handled at this point so this
	 * should be impossible.  But handle it in the caller either way.
	 */
	if (rl_to_sval(left_orig, &left_sval))
		return false;

	// TODO: it might be safer to say that known possible NULL or error
	// error pointers return false.

	*res = clone_rl(valid_ptr_rl);

	return true;
}

static bool max_is_unknown_max(struct range_list *rl)
{
	/*
	 * The issue with this code is that we had:
	 * if (foo > 1) return 1 - foo;
	 * Ideally we would say that returns s32min-(-1) but what Smatch
	 * was saying was that the lowest possible value was "1 - INT_MAX"
	 *
	 * My solution is to ignore max values for int or larger.  I keep
	 * the max for shorts etc, because those might be worthwhile.
	 *
	 * The problem with just returning 1 - INT_MAX is that that is
	 * treated as useful information but s32min is treated as basically
	 * unknown.
	 */

	if (type_bits(rl_type(rl)) < 31)
		return false;
	return sval_is_max(rl_max(rl));
}

static bool handle_add_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
	struct range_list *left_rl = NULL;
	struct range_list *right_rl = NULL;
	struct range_list *valid;
	struct symbol *type;
	sval_t min, max;

	type = get_type(expr);

	get_rl_internal(expr->left, implied, recurse_cnt, &left_rl);
	left_rl = cast_rl(type, left_rl);
	get_rl_internal(expr->right, implied, recurse_cnt, &right_rl);
	right_rl = cast_rl(type, right_rl);

	if (!left_rl)
		return false;

	if (type_is_ptr(type) && !var_user_rl(expr->right)) {
		valid = rl_intersection(left_rl, valid_ptr_rl);
		if (valid && rl_equiv(valid, left_rl))
			return valid_ptr_rl;
	}

	if (!right_rl)
		return false;

	if (sval_binop_overflows(rl_min(left_rl), expr->op, rl_min(right_rl)))
		return false;
	if (sval_binop_overflows(rl_max(left_rl), expr->op, rl_max(right_rl)))
		return false;

	min = sval_binop(rl_min(left_rl), expr->op, rl_min(right_rl));
	max = sval_binop(rl_max(left_rl), expr->op, rl_max(right_rl));

	*res = alloc_rl(min, max);
	return true;
}

static bool handle_subtract_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
	struct symbol *type;
	struct range_list *left_orig, *right_orig;
	struct range_list *left_rl, *right_rl;
	sval_t min, max, tmp;
	int comparison;
	int offset;

	type = get_type(expr);

	offset = handle_offset_subtraction(expr);
	if (offset >= 0) {
		tmp.type = type;
		tmp.value = offset;

		*res = alloc_rl(tmp, tmp);
		return true;
	}

	if (handle_container_of(expr, implied, recurse_cnt, res))
		return true;

	comparison = get_comparison(expr->left, expr->right);

	left_orig = NULL;
	get_rl_internal(expr->left, implied, recurse_cnt, &left_orig);
	left_rl = cast_rl(type, left_orig);
	right_orig = NULL;
	get_rl_internal(expr->right, implied, recurse_cnt, &right_orig);
	right_rl = cast_rl(type, right_orig);

	if ((!left_rl || !right_rl) &&
	    (implied == RL_EXACT || implied == RL_HARD || implied == RL_FUZZY))
		return false;

	if (!left_rl)
		left_rl = alloc_whole_rl(type);
	if (!right_rl)
		right_rl = alloc_whole_rl(type);

	/* negative values complicate everything fix this later */
	if (sval_is_negative(rl_min(right_rl)))
		return false;
	max = rl_max(left_rl);
	min = sval_type_min(type);

	switch (comparison) {
	case '>':
	case SPECIAL_UNSIGNED_GT:
		min = sval_type_val(type, 1);
		max = rl_max(left_rl);
		break;
	case SPECIAL_GTE:
	case SPECIAL_UNSIGNED_GTE:
		min = sval_type_val(type, 0);
		max = rl_max(left_rl);
		break;
	case SPECIAL_EQUAL:
		min = sval_type_val(type, 0);
		max = sval_type_val(type, 0);
		break;
	case '<':
	case SPECIAL_UNSIGNED_LT:
		max = sval_type_val(type, -1);
		break;
	case SPECIAL_LTE:
	case SPECIAL_UNSIGNED_LTE:
		max = sval_type_val(type, 0);
		break;
	default:
		if (!left_orig || !right_orig)
			return false;
		*res = rl_binop(left_rl, '-', right_rl);
		return true;
	}

	if (!max_is_unknown_max(right_rl) &&
	    !sval_binop_overflows(rl_min(left_rl), '-', rl_max(right_rl))) {
		tmp = sval_binop(rl_min(left_rl), '-', rl_max(right_rl));
		if (sval_cmp(tmp, min) > 0)
			min = tmp;
	}

	if (!sval_is_max(rl_max(left_rl))) {
		tmp = sval_binop(rl_max(left_rl), '-', rl_min(right_rl));
		if (sval_cmp(tmp, max) < 0)
			max = tmp;
	}

	if (sval_is_min(min) && sval_is_max(max))
		return false;

	*res = cast_rl(type, alloc_rl(min, max));
	return true;
}

static bool handle_mod_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
	struct range_list *rl;
	sval_t left, right, sval;

	if (implied == RL_EXACT) {
		if (!get_implied_value(expr->right, &right))
			return false;
		if (!get_implied_value(expr->left, &left))
			return false;
		sval = sval_binop(left, '%', right);
		*res = alloc_rl(sval, sval);
		return true;
	}
	/* if we can't figure out the right side it's probably hopeless */
	if (!get_implied_value_internal(expr->right, recurse_cnt, &right))
		return false;

	right = sval_cast(get_type(expr), right);
	right.value--;

	if (get_rl_internal(expr->left, implied, recurse_cnt, &rl) && rl &&
	    rl_max(rl).uvalue < right.uvalue)
		right.uvalue = rl_max(rl).uvalue;

	*res = alloc_rl(sval_cast(right.type, zero), right);
	return true;
}

static bool handle_bitwise_AND(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
	struct symbol *type;
	struct range_list *left_rl, *right_rl;
	int new_recurse;

	if (implied != RL_IMPLIED && implied != RL_ABSOLUTE && implied != RL_REAL_ABSOLUTE)
		return false;

	type = get_type(expr);

	if (!get_rl_internal(expr->left, implied, recurse_cnt, &left_rl))
		left_rl = alloc_whole_rl(type);
	left_rl = cast_rl(type, left_rl);

	new_recurse = *recurse_cnt;
	if (*recurse_cnt >= 200)
		new_recurse = 100;  /* Let's try super hard to get the mask */
	if (!get_rl_internal(expr->right, implied, &new_recurse, &right_rl))
		right_rl = alloc_whole_rl(type);
	right_rl = cast_rl(type, right_rl);
	*recurse_cnt = new_recurse;

	*res = rl_binop(left_rl, '&', right_rl);
	return true;
}

static bool use_rl_binop(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
	struct symbol *type;
	struct range_list *left_rl, *right_rl;

	if (implied != RL_IMPLIED && implied != RL_ABSOLUTE && implied != RL_REAL_ABSOLUTE)
		return false;

	type = get_type(expr);

	get_absolute_rl_internal(expr->left, &left_rl, recurse_cnt);
	get_absolute_rl_internal(expr->right, &right_rl, recurse_cnt);
	left_rl = cast_rl(type, left_rl);
	right_rl = cast_rl(type, right_rl);
	if (!left_rl || !right_rl)
		return false;

	*res = rl_binop(left_rl, expr->op, right_rl);
	return true;
}

static bool handle_right_shift(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
	struct range_list *left_rl, *right_rl;
	sval_t min, max;

	if (implied == RL_EXACT || implied == RL_HARD)
		return false;

	if (get_rl_internal(expr->left, implied, recurse_cnt, &left_rl)) {
		max = rl_max(left_rl);
		min = rl_min(left_rl);
	} else {
		if (implied == RL_FUZZY)
			return false;
		max = sval_type_max(get_type(expr->left));
		min = sval_type_val(get_type(expr->left), 0);
	}

	if (get_rl_internal(expr->right, implied, recurse_cnt, &right_rl) &&
	    !sval_is_negative(rl_min(right_rl))) {
		min = sval_binop(min, SPECIAL_RIGHTSHIFT, rl_max(right_rl));
		max = sval_binop(max, SPECIAL_RIGHTSHIFT, rl_min(right_rl));
	} else if (!sval_is_negative(min)) {
		min.value = 0;
		max = sval_type_max(max.type);
	} else {
		return false;
	}

	*res = alloc_rl(min, max);
	return true;
}

static bool handle_left_shift(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
	struct range_list *left_rl, *rl;
	sval_t right;

	if (implied == RL_EXACT || implied == RL_HARD)
		return false;
	/* this is hopeless without the right side */
	if (!get_implied_value_internal(expr->right, recurse_cnt, &right))
		return false;
	if (!get_rl_internal(expr->left, implied, recurse_cnt, &left_rl)) {
		if (implied == RL_FUZZY)
			return false;
		left_rl = alloc_whole_rl(get_type(expr->left));
	}

	rl = rl_binop(left_rl, SPECIAL_LEFTSHIFT, alloc_rl(right, right));
	if (!rl)
		return false;
	*res = rl;
	return true;
}

static bool handle_known_binop(struct expression *expr, sval_t *res)
{
	sval_t left, right;

	if (!get_value(expr->left, &left))
		return false;
	if (!get_value(expr->right, &right))
		return false;
	*res = sval_binop(left, expr->op, right);
	return true;
}

static int has_actual_ranges(struct range_list *rl)
{
	struct data_range *tmp;

	FOR_EACH_PTR(rl, tmp) {
		if (sval_cmp(tmp->min, tmp->max) != 0)
			return 1;
	} END_FOR_EACH_PTR(tmp);
	return 0;
}

static struct range_list *handle_implied_binop(struct range_list *left_rl, int op, struct range_list *right_rl)
{
	struct range_list *res_rl;
	struct data_range *left_drange, *right_drange;
	sval_t res;

	if (!left_rl || !right_rl)
		return NULL;
	if (has_actual_ranges(left_rl))
		return NULL;
	if (has_actual_ranges(right_rl))
		return NULL;

	if (ptr_list_size((struct ptr_list *)left_rl) * ptr_list_size((struct ptr_list *)right_rl) > 20)
		return NULL;

	res_rl = NULL;

	FOR_EACH_PTR(left_rl, left_drange) {
		FOR_EACH_PTR(right_rl, right_drange) {
			if ((op == '%' || op == '/') &&
			    right_drange->min.value == 0)
				return NULL;
			res = sval_binop(left_drange->min, op, right_drange->min);
			add_range(&res_rl, res, res);
		} END_FOR_EACH_PTR(right_drange);
	} END_FOR_EACH_PTR(left_drange);

	return res_rl;
}

static bool handle_binop_rl_helper(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct symbol *type;
	struct range_list *left_rl = NULL;
	struct range_list *right_rl = NULL;
	struct range_list *rl;
	sval_t min, max;

	type = get_promoted_type(get_type(expr->left), get_type(expr->right));
	get_rl_internal(expr->left, implied, recurse_cnt, &left_rl);
	left_rl = cast_rl(type, left_rl);
	get_rl_internal(expr->right, implied, recurse_cnt, &right_rl);
	right_rl = cast_rl(type, right_rl);

	rl = handle_implied_binop(left_rl, expr->op, right_rl);
	if (rl) {
		*res = rl;
		return true;
	}

	switch (expr->op) {
	case '%':
		return handle_mod_rl(expr, implied, recurse_cnt, res);
	case '&':
		return handle_bitwise_AND(expr, implied, recurse_cnt, res);
	case '|':
	case '^':
		return use_rl_binop(expr, implied, recurse_cnt, res);
	case SPECIAL_RIGHTSHIFT:
		return handle_right_shift(expr, implied, recurse_cnt, res);
	case SPECIAL_LEFTSHIFT:
		return handle_left_shift(expr, implied, recurse_cnt, res);
	case '+':
		return handle_add_rl(expr, implied, recurse_cnt, res);
	case '-':
		return handle_subtract_rl(expr, implied, recurse_cnt, res);
	case '/':
		return handle_divide_rl(expr, implied, recurse_cnt, res);
	}

	if (!left_rl || !right_rl)
		return false;

	if (sval_binop_overflows(rl_min(left_rl), expr->op, rl_min(right_rl)))
		return false;
	if (sval_binop_overflows(rl_max(left_rl), expr->op, rl_max(right_rl)))
		return false;

	min = sval_binop(rl_min(left_rl), expr->op, rl_min(right_rl));
	max = sval_binop(rl_max(left_rl), expr->op, rl_max(right_rl));

	*res = alloc_rl(min, max);
	return true;

}

static bool handle_binop_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct smatch_state *state;
	struct range_list *rl;
	sval_t val;

	if (expr->sval) {
		*res_sval = *expr->sval;
		return true;
	}

	if (handle_known_binop(expr, &val)) {
		expr->sval = malloc(sizeof(sval_t));
		*expr->sval = val;
		*res_sval = val;
		return true;
	}
	if (implied == RL_EXACT)
		return false;

	if (custom_handle_variable) {
		rl = custom_handle_variable(expr);
		if (rl) {
			*res = rl;
			return true;
		}
	}

	state = get_extra_state(expr);
	if (state && !is_whole_rl(estate_rl(state))) {
		if (implied != RL_HARD || estate_has_hard_max(state)) {
			*res = clone_rl(estate_rl(state));
			return true;
		}
	}

	return handle_binop_rl_helper(expr, implied, recurse_cnt, res, res_sval);
}

static int do_comparison(struct expression *expr)
{
	struct range_list *left_ranges = NULL;
	struct range_list *right_ranges = NULL;
	int poss_true, poss_false;
	struct symbol *type;

	type = get_type(expr);
	get_absolute_rl(expr->left, &left_ranges);
	get_absolute_rl(expr->right, &right_ranges);

	left_ranges = cast_rl(type, left_ranges);
	right_ranges = cast_rl(type, right_ranges);

	poss_true = possibly_true_rl(left_ranges, expr->op, right_ranges);
	poss_false = possibly_false_rl(left_ranges, expr->op, right_ranges);

	if (!poss_true && !poss_false)
		return 0x0;
	if (poss_true && !poss_false)
		return 0x1;
	if (!poss_true && poss_false)
		return 0x2;
	return 0x3;
}

static bool handle_comparison_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	sval_t left, right;
	int cmp;

	if (expr->op == SPECIAL_EQUAL && expr->left->type == EXPR_TYPE) {
		struct symbol *left, *right;

		if (expr->right->type != EXPR_TYPE)
			return false;

		left = get_real_base_type(expr->left->symbol);
		right = get_real_base_type(expr->right->symbol);

		while (type_is_ptr(left) || type_is_ptr(right)) {

			if ((type_is_ptr(left) && !type_is_ptr(right)) ||
			    (!type_is_ptr(left) && type_is_ptr(right))) {
				*res_sval = zero;
				return true;
			}

			left = get_real_base_type(left);
			right = get_real_base_type(right);
		}

		if (type_bits(left) == type_bits(right) &&
		    type_positive_bits(left) == type_positive_bits(right))
			*res_sval = one;
		else
			*res_sval = zero;
		return true;
	}

	if (get_value(expr->left, &left) && get_value(expr->right, &right)) {
		struct data_range tmp_left, tmp_right;

		tmp_left.min = left;
		tmp_left.max = left;
		tmp_right.min = right;
		tmp_right.max = right;
		if (true_comparison_range(&tmp_left, expr->op, &tmp_right))
			*res_sval = one;
		else
			*res_sval = zero;
		return true;
	}

	if (implied == RL_EXACT)
		return false;

	cmp = do_comparison(expr);
	if (cmp == 1) {
		*res_sval = one;
		return true;
	}
	if (cmp == 2) {
		*res_sval = zero;
		return true;
	}

	*res = alloc_rl(zero, one);
	return true;
}

static bool handle_logical_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	sval_t left, right;
	int left_known = 0;
	int right_known = 0;

	if (implied == RL_EXACT) {
		if (get_value(expr->left, &left))
			left_known = 1;
		if (get_value(expr->right, &right))
			right_known = 1;
	} else {
		if (get_implied_value_internal(expr->left, recurse_cnt, &left))
			left_known = 1;
		if (get_implied_value_internal(expr->right, recurse_cnt, &right))
			right_known = 1;
	}

	switch (expr->op) {
	case SPECIAL_LOGICAL_OR:
		if (left_known && left.value)
			goto one;
		if (right_known && right.value)
			goto one;
		if (left_known && right_known)
			goto zero;
		break;
	case SPECIAL_LOGICAL_AND:
		if (left_known && left.value == 0)
			goto zero;
		if (right_known && right.value == 0)
			goto zero;
		if (left_known && right_known)
			goto one;
		break;
	default:
		return false;
	}

	if (implied == RL_EXACT)
		return false;

	*res = alloc_rl(zero, one);
	return true;

zero:
	*res_sval = zero;
	return true;
one:
	*res_sval = one;
	return true;
}

static bool handle_conditional_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct expression *cond_true;
	struct range_list *true_rl, *false_rl;
	struct symbol *type;

	cond_true = expr->cond_true;
	if (!cond_true)
		cond_true = expr->conditional;

	if (known_condition_true(expr->conditional))
		return get_rl_sval(cond_true, implied, recurse_cnt, res, res_sval);
	if (known_condition_false(expr->conditional))
		return get_rl_sval(expr->cond_false, implied, recurse_cnt, res, res_sval);

	if (implied == RL_EXACT)
		return false;

	if (implied_condition_true(expr->conditional))
		return get_rl_sval(cond_true, implied, recurse_cnt, res, res_sval);
	if (implied_condition_false(expr->conditional))
		return get_rl_sval(expr->cond_false, implied, recurse_cnt, res, res_sval);

	/* this becomes a problem with deeply nested conditional statements */
	if (fast_math_only || low_on_memory())
		return false;

	type = get_type(expr);

	init_fake_env();
	__split_whole_condition(expr->conditional);
	true_rl = NULL;
	get_rl_internal(cond_true, implied, recurse_cnt, &true_rl);
	__push_true_states();
	__use_false_states();
	false_rl = NULL;
	get_rl_internal(expr->cond_false, implied, recurse_cnt, &false_rl);
	__merge_true_states();
	end_fake_env();

	if (!true_rl || !false_rl)
		return false;
	true_rl = cast_rl(type, true_rl);
	false_rl = cast_rl(type, false_rl);

	*res = rl_union(true_rl, false_rl);
	return true;
}

static bool get_fuzzy_max_helper(struct expression *expr, sval_t *max)
{
	struct smatch_state *state;
	sval_t sval;

	if (get_hard_max(expr, &sval)) {
		*max = sval;
		return true;
	}

	state = get_extra_state(expr);
	if (!state || !estate_has_fuzzy_max(state))
		return false;
	*max = sval_cast(get_type(expr), estate_get_fuzzy_max(state));
	return true;
}

static bool get_fuzzy_min_helper(struct expression *expr, sval_t *min)
{
	struct smatch_state *state;
	sval_t sval;

	state = get_extra_state(expr);
	if (!state || !estate_rl(state))
		return false;

	sval = estate_min(state);
	if (sval_is_negative(sval) && sval_is_min(sval))
		return false;

	if (sval_is_max(sval))
		return false;

	*min = sval_cast(get_type(expr), sval);
	return true;
}

int get_const_value(struct expression *expr, sval_t *sval)
{
	struct symbol *sym;
	sval_t right;

	if (expr->type != EXPR_SYMBOL || !expr->symbol)
		return 0;
	sym = expr->symbol;
	if (!(sym->ctype.modifiers & MOD_CONST))
		return 0;
	if (get_value(sym->initializer, &right)) {
		*sval = sval_cast(get_type(expr), right);
		return 1;
	}
	return 0;
}

struct range_list *var_to_absolute_rl(struct expression *expr)
{
	struct smatch_state *state;
	struct range_list *rl;

	state = get_extra_state(expr);
	if (!state || is_whole_rl(estate_rl(state))) {
		state = get_real_absolute_state(expr);
		if (state && state->data && !estate_is_whole(state))
			return clone_rl(estate_rl(state));
		if (get_mtag_rl(expr, &rl))
			return rl;
		if (get_db_type_rl(expr, &rl) && !is_whole_rl(rl))
			return rl;
		return alloc_whole_rl(get_type(expr));
	}
	return clone_rl(estate_rl(state));
}

static bool is_param_sym(struct expression *expr)
{
	if (expr->type != EXPR_SYMBOL)
		return false;
	if (get_param_num(expr) < 0)
		return false;
	return true;
}

static bool handle_variable(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct smatch_state *state;
	struct range_list *rl;
	sval_t sval, min, max;
	struct symbol *type;

	if (get_const_value(expr, &sval)) {
		*res_sval = sval;
		return true;
	}

	if (implied == RL_EXACT)
		return false;

	if (custom_handle_variable) {
		rl = custom_handle_variable(expr);
		if (rl) {
			if (!rl_to_sval(rl, res_sval))
				*res = rl;
		} else {
			*res = var_to_absolute_rl(expr);
		}
		return true;
	}

	if (get_mtag_sval(expr, &sval)) {
		*res_sval = sval;
		return true;
	}

	type = get_type(expr);
	if (type &&
	    ((type->type == SYM_ARRAY && !is_param_sym(expr)) ||
	     type->type == SYM_FN))
		return handle_address(expr, implied, recurse_cnt, res, res_sval);

	/* FIXME: call rl_to_sval() on the results */

	switch (implied) {
	case RL_HARD:
	case RL_IMPLIED:
	case RL_ABSOLUTE:
		state = get_extra_state(expr);
		if (!state) {
			if (implied == RL_HARD)
				return false;
			if (get_mtag_rl(expr, res))
				return true;
			if (is_array(expr) && get_array_rl(expr, res))
				return true;
			if (implied == RL_IMPLIED)
				return false;
			if (get_db_type_rl(expr, res))
				return true;
			return false;
		}
		if (implied == RL_HARD && !estate_has_hard_max(state))
			return false;
		*res = clone_rl(estate_rl(state));
		return true;
	case RL_REAL_ABSOLUTE: {
		struct smatch_state *abs_state;

		state = get_extra_state(expr);
		abs_state = get_real_absolute_state(expr);

		if (estate_rl(state) && estate_rl(abs_state)) {
			*res = clone_rl(rl_intersection(estate_rl(state),
							estate_rl(abs_state)));
			return true;
		} else if (estate_rl(state)) {
			*res = clone_rl(estate_rl(state));
			return true;
		} else if (estate_is_empty(state)) {
			/*
			 * FIXME: we don't handle empty extra states correctly.
			 *
			 * The real abs rl is supposed to be filtered by the
			 * extra state if there is one.  We don't bother keeping
			 * the abs state in sync all the time because we know it
			 * will be filtered later.
			 *
			 * It's not totally obvious to me how they should be
			 * handled.  Perhaps we should take the whole rl and
			 * filter by the imaginary states.  Perhaps we should
			 * just go with the empty state.
			 *
			 * Anyway what we currently do is return NULL here and
			 * that gets translated into the whole range in
			 * get_real_absolute_rl().
			 *
			 */
			return false;
		} else if (estate_rl(abs_state)) {
			*res = clone_rl(estate_rl(abs_state));
			return true;
		}

		if (get_mtag_rl(expr, res))
			return true;
		if (get_db_type_rl(expr, res))
			return true;
		if (is_array(expr) && get_array_rl(expr, res))
			return true;
		return false;
	}
	case RL_FUZZY:
		if (!get_fuzzy_min_helper(expr, &min))
			min = sval_type_min(get_type(expr));
		if (!get_fuzzy_max_helper(expr, &max))
			return false;
		/* fuzzy ranges are often inverted */
		if (sval_cmp(min, max) > 0) {
			sval = min;
			min = max;
			max = sval;
		}
		*res = alloc_rl(min, max);
		return true;
	}
	return false;
}

static sval_t handle_sizeof(struct expression *expr)
{
	struct symbol *sym;
	sval_t ret;

	ret = sval_blank(expr);
	sym = expr->cast_type;
	if (!sym) {
		sym = evaluate_expression(expr->cast_expression);
		if (!sym) {
			__silence_warnings_for_stmt = true;
			sym = &int_ctype;
		}
#if 0
		/*
		 * Expressions of restricted types will possibly get
		 * promoted - check that here.  I'm not sure how this works,
		 * the problem is that sizeof(le16) shouldn't be promoted and
		 * the original code did that...  Let's if zero this out and
		 * see what breaks.
		 */

		if (is_restricted_type(sym)) {
			if (type_bits(sym) < bits_in_int)
				sym = &int_ctype;
		}
#endif
		if (is_fouled_type(sym))
			sym = &int_ctype;
	}
	examine_symbol_type(sym);

	ret.type = size_t_ctype;
	if (type_bits(sym) <= 0) /* sizeof(void) */ {
		if (get_real_base_type(sym) == &void_ctype)
			ret.value = 1;
		else
			ret.value = 0;
	} else
		ret.value = type_bytes(sym);

	return ret;
}

static bool handle_strlen(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct expression *arg, *tmp;
	sval_t tag;
	sval_t ret = { .type = &ulong_ctype };
	struct range_list *rl;

	arg = get_argument_from_call_expr(expr->args, 0);
	if (!arg)
		return false;
	if (arg->type == EXPR_STRING) {
		ret.value = arg->string->length - 1;
		*res_sval = ret;
		return true;
	}
	if (implied == RL_EXACT)
		return false;
	if (get_implied_value(arg, &tag) &&
	    (tmp = fake_string_from_mtag(tag.uvalue))) {
		ret.value = tmp->string->length - 1;
		*res_sval = ret;
		return true;
	}

	if (implied == RL_HARD || implied == RL_FUZZY)
		return false;

	if (get_implied_return(expr, &rl)) {
		*res = rl;
		return true;
	}

	return false;
}

static bool handle_builtin_constant_p(struct expression *expr, int implied, int *recurse_cnt, sval_t *res_sval)
{
	struct expression *arg, *assigned;
	struct range_list *rl;
	static bool nested;

	arg = get_argument_from_call_expr(expr->args, 0);
	/*
	 * Originally, Smatch used to pretend there were no constants but then
	 * it turned out that we need to know at build time if some paths are
	 * impossible or not to avoid crazy false positives.
	 *
	 * But then someone added a BUILD_BUG_ON(!__builtin_constant_p(_mask)).
	 * So now we try to figure out if GCC can determine the value at
	 * build time.
	 */
	if (get_rl_internal(arg, RL_EXACT, recurse_cnt, &rl)) {
		*res_sval = one;
		return true;
	}

	if (nested) {
		*res_sval = zero;
		return true;
	}

	assigned = get_assigned_expr(arg);
	nested = true;
	if (assigned && get_rl_internal(assigned, RL_EXACT, recurse_cnt, &rl))
		*res_sval = one;
	else
		*res_sval = zero;
	nested = false;

	return true;
}

static bool handle__builtin_choose_expr(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct expression *const_expr, *expr1, *expr2;
	sval_t sval;

	const_expr = get_argument_from_call_expr(expr->args, 0);
	expr1 = get_argument_from_call_expr(expr->args, 1);
	expr2 = get_argument_from_call_expr(expr->args, 2);

	if (!get_value(const_expr, &sval) || !expr1 || !expr2)
		return false;
	if (sval.value)
		return get_rl_sval(expr1, implied, recurse_cnt, res, res_sval);
	else
		return get_rl_sval(expr2, implied, recurse_cnt, res, res_sval);
}

int smatch_fls(unsigned long long value)
{
	int i;

	for (i = 63; i >= 0; i--) {
		if (value & 1ULL << i)
			return i + 1;
	}
	return 0;
}

static bool handle_ffs(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct expression *arg;
	struct bit_info *bits;
	sval_t high = { .type = &int_ctype };
	sval_t low = { .type = &int_ctype };

	arg = get_argument_from_call_expr(expr->args, 0);

	bits = get_bit_info(arg);
	if (bits->possible == 0) {
		high.value = 0;
		*res_sval = high;
		return true;
	}

	high.value = ffsll(bits->set);
	if (!high.value)
		high.value = smatch_fls(bits->possible);

	low.value = ffsll(bits->possible);

	*res = alloc_rl(low, high);
	return false;
}

static bool handle_call_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct range_list *rl;

	if (sym_name_is("__builtin_constant_p", expr->fn))
		return handle_builtin_constant_p(expr, implied, recurse_cnt, res_sval);

	if (sym_name_is("__builtin_choose_expr", expr->fn))
		return handle__builtin_choose_expr(expr, implied, recurse_cnt, res, res_sval);

	if (sym_name_is("__builtin_expect", expr->fn) ||
	    sym_name_is("__builtin_bswap16", expr->fn) ||
	    sym_name_is("__builtin_bswap32", expr->fn) ||
	    sym_name_is("__builtin_bswap64", expr->fn)) {
		struct expression *arg;

		arg = get_argument_from_call_expr(expr->args, 0);
		return get_rl_sval(arg, implied, recurse_cnt, res, res_sval);
	}

	if (sym_name_is("__builtin_ffs", expr->fn) ||
	    sym_name_is("__builtin_ffsl", expr->fn) ||
	    sym_name_is("__builtin_ffsll", expr->fn) ||
	    sym_name_is("__ffs", expr->fn))
		return handle_ffs(expr, implied, recurse_cnt, res, res_sval);

	if (sym_name_is("strlen", expr->fn))
		return handle_strlen(expr, implied, recurse_cnt, res, res_sval);

	if (implied == RL_EXACT || implied == RL_HARD)
		return false;

	if (custom_handle_variable) {
		rl = custom_handle_variable(expr);
		if (rl) {
			*res = rl;
			return true;
		}
	}

	/* Ugh...  get_implied_return() sets *rl to NULL on failure */
	if (get_implied_return(expr, &rl)) {
		*res = rl;
		return true;
	}
	rl = db_return_vals(expr);
	if (rl) {
		*res = rl;
		return true;
	}
	return false;
}

static bool handle_cast(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct range_list *rl;
	struct symbol *type;
	sval_t sval = {};

	type = get_type(expr);
	if (get_rl_sval(expr->cast_expression, implied, recurse_cnt, &rl, &sval)) {
		if (sval.type)
			*res_sval = sval_cast(type, sval);
		else
			*res = cast_rl(type, rl);
		return true;
	}
	if (implied == RL_ABSOLUTE || implied == RL_REAL_ABSOLUTE) {
		*res = alloc_whole_rl(type);
		return true;
	}
	if (implied == RL_IMPLIED && type &&
	    type_bits(type) > 0 && type_bits(type) < 32) {
		*res = alloc_whole_rl(type);
		return true;
	}
	return false;
}

static bool handle_offsetof_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
	struct expression *down = expr->down;
	struct range_list *offset_rl = NULL, *down_rl = NULL;
	sval_t sval = { .type = ssize_t_ctype };
	struct symbol *type;

	type = get_real_base_type(expr->in);
	if (!type)
		return false;

	if (expr->op == '.') {
		struct symbol *field;
		int offset = 0;

		field = find_identifier(expr->ident, type->symbol_list, &offset);
		if (!field)
			return false;

		sval.value = offset;
		offset_rl = alloc_rl(sval, sval);
		type = field;
	} else {
		if (!expr->index) {
			sval.value = 0;
			offset_rl = alloc_rl(sval, sval);
		} else {
			struct range_list *idx_rl = NULL, *bytes_rl;

			if (get_rl_internal(expr->index, implied, recurse_cnt, &idx_rl))
				return false;

			sval.value = type_bytes(type);
			if (sval.value <= 0)
				return false;
			bytes_rl = alloc_rl(sval, sval);

			offset_rl = rl_binop(idx_rl, '*', bytes_rl);
		}
	}

	if (down) {
		if (down->type == EXPR_OFFSETOF && !down->in)
			down->in = type;
		if (!get_rl_internal(down, implied, recurse_cnt, &down_rl))
			return false;

		*res = rl_binop(offset_rl, '+', down_rl);
	} else {
		*res = offset_rl;
	}

	return true;
}

static bool get_rl_sval(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *sval_res)
{
	struct range_list *rl = (void *)-1UL;
	struct symbol *type;
	sval_t sval = {};

	type = get_type(expr);
	expr = strip_parens(expr);
	if (!expr)
		return false;

	if (++(*recurse_cnt) >= 200)
		return false;

	switch(expr->type) {
	case EXPR_CAST:
	case EXPR_FORCE_CAST:
	case EXPR_IMPLIED_CAST:
		handle_cast(expr, implied, recurse_cnt, &rl, &sval);
		goto out_cast;
	}

	expr = strip_expr(expr);
	if (!expr)
		return false;

	switch (expr->type) {
	case EXPR_VALUE:
		sval = sval_from_val(expr, expr->value);
		break;
	case EXPR_FVALUE:
		sval = sval_from_fval(expr, expr->fvalue);
		break;
	case EXPR_PREOP:
		handle_preop_rl(expr, implied, recurse_cnt, &rl, &sval);
		break;
	case EXPR_POSTOP:
		get_rl_sval(expr->unop, implied, recurse_cnt, &rl, &sval);
		break;
	case EXPR_BINOP:
		handle_binop_rl(expr, implied, recurse_cnt, &rl, &sval);
		break;
	case EXPR_COMPARE:
		handle_comparison_rl(expr, implied, recurse_cnt, &rl, &sval);
		break;
	case EXPR_LOGICAL:
		handle_logical_rl(expr, implied, recurse_cnt, &rl, &sval);
		break;
	case EXPR_PTRSIZEOF:
	case EXPR_SIZEOF:
		sval = handle_sizeof(expr);
		break;
	case EXPR_SELECT:
	case EXPR_CONDITIONAL:
		handle_conditional_rl(expr, implied, recurse_cnt, &rl, &sval);
		break;
	case EXPR_CALL:
		handle_call_rl(expr, implied, recurse_cnt, &rl, &sval);
		break;
	case EXPR_STRING:
		if (get_mtag_sval(expr, &sval))
			break;
		if (implied == RL_EXACT)
			break;
		rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
		break;
	case EXPR_OFFSETOF:
		handle_offsetof_rl(expr, implied, recurse_cnt, &rl, &sval);
		break;
	case EXPR_ALIGNOF:
		evaluate_expression(expr);
		if (expr->type == EXPR_VALUE)
			sval = sval_from_val(expr, expr->value);
		break;
	default:
		handle_variable(expr, implied, recurse_cnt, &rl, &sval);
	}

out_cast:
	if (rl == (void *)-1UL)
		rl = NULL;

	if (sval.type || (rl && rl_to_sval(rl, &sval))) {
		*sval_res = sval;
		return true;
	}
	if (implied == RL_EXACT)
		return false;

	if (rl) {
		*res = rl;
		return true;
	}
	if (type && (implied == RL_ABSOLUTE || implied == RL_REAL_ABSOLUTE) &&
	    !custom_handle_variable) {
		*res = alloc_whole_rl(type);
		return true;
	}
	return false;
}

static bool get_rl_internal(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
	struct range_list *rl = NULL;
	sval_t sval = {};

	if (!get_rl_sval(expr, implied, recurse_cnt, &rl, &sval))
		return false;

	if (sval.type)
		*res = alloc_rl(sval, sval);
	else
		*res = rl;
	return true;
}

static bool get_rl_helper(struct expression *expr, int implied, struct range_list **res)
{
	struct range_list *rl = NULL;
	sval_t sval = {};
	int recurse_cnt = 0;

	if (get_value(expr, &sval)) {
		if (implied == RL_HARD) {
			if (sval.uvalue == INT_MAX ||
			    sval.uvalue == UINT_MAX ||
			    sval.uvalue == LONG_MAX ||
			    sval.uvalue == ULONG_MAX)
				return false;
		}
		*res = alloc_rl(sval, sval);
		return true;
	}

	if (!get_rl_sval(expr, implied, &recurse_cnt, &rl, &sval))
		return false;

	if (sval.type)
		*res = alloc_rl(sval, sval);
	else
		*res = rl;
	return true;
}

static struct {
	struct expression *expr;
	sval_t sval;
} cached_results[24];
static int cache_idx;

void clear_math_cache(void)
{
	memset(cached_results, 0, sizeof(cached_results));
}

void set_fast_math_only(void)
{
	fast_math_only++;
}

void clear_fast_math_only(void)
{
	fast_math_only--;
}

/*
 * Don't cache EXPR_VALUE because values are fast already.
 *
 */
static bool get_value_literal(struct expression *expr, sval_t *res_sval)
{
	struct expression *tmp;
	int recurse_cnt = 0;

	tmp = strip_expr(expr);
	if (!tmp || tmp->type != EXPR_VALUE)
		return false;

	return get_rl_sval(expr, RL_EXACT, &recurse_cnt, NULL, res_sval);
}

/* returns 1 if it can get a value literal or else returns 0 */
int get_value(struct expression *expr, sval_t *res_sval)
{
	struct range_list *(*orig_custom_fn)(struct expression *expr);
	int recurse_cnt = 0;
	sval_t sval = {};
	int i;

	if (get_value_literal(expr, res_sval))
		return 1;

	/*
	 * This only handles RL_EXACT because other expr statements can be
	 * different at different points.  Like the list iterator, for example.
	 */
	for (i = 0; i < ARRAY_SIZE(cached_results); i++) {
		if (expr == cached_results[i].expr) {
			if (cached_results[i].sval.type) {
				*res_sval = cached_results[i].sval;
				return true;
			}
			return false;
		}
	}

	orig_custom_fn = custom_handle_variable;
	custom_handle_variable = NULL;
	get_rl_sval(expr, RL_EXACT, &recurse_cnt, NULL, &sval);

	custom_handle_variable = orig_custom_fn;

	cached_results[cache_idx].expr = expr;
	cached_results[cache_idx].sval = sval;
	cache_idx = (cache_idx + 1) % ARRAY_SIZE(cached_results);

	if (!sval.type)
		return 0;

	*res_sval = sval;
	return 1;
}

static bool get_implied_value_internal(struct expression *expr, int *recurse_cnt, sval_t *res_sval)
{
	struct range_list *rl;

	res_sval->type = NULL;

	if (!get_rl_sval(expr, RL_IMPLIED, recurse_cnt, &rl, res_sval))
		return false;
	if (!res_sval->type && !rl_to_sval(rl, res_sval))
		return false;
	return true;
}

int get_implied_value(struct expression *expr, sval_t *sval)
{
	struct range_list *rl;

	if (!get_rl_helper(expr, RL_IMPLIED, &rl) ||
	    !rl_to_sval(rl, sval))
		return 0;
	return 1;
}

int get_implied_value_fast(struct expression *expr, sval_t *sval)
{
	struct range_list *rl;
	static int recurse;
	int ret = 0;

	if (recurse)
		return 0;

	recurse = 1;
	set_fast_math_only();
	if (get_rl_helper(expr, RL_IMPLIED, &rl) &&
	    rl_to_sval(rl, sval))
		ret = 1;
	clear_fast_math_only();
	recurse = 0;

	return ret;
}

int get_implied_min(struct expression *expr, sval_t *sval)
{
	struct range_list *rl;

	if (!get_rl_helper(expr, RL_IMPLIED, &rl) || !rl)
		return 0;
	*sval = rl_min(rl);
	return 1;
}

int get_implied_max(struct expression *expr, sval_t *sval)
{
	struct range_list *rl;

	if (!get_rl_helper(expr, RL_IMPLIED, &rl) || !rl)
		return 0;
	*sval = rl_max(rl);
	return 1;
}

int get_implied_rl(struct expression *expr, struct range_list **rl)
{
	if (!get_rl_helper(expr, RL_IMPLIED, rl) || !*rl)
		return 0;
	return 1;
}

static int get_absolute_rl_internal(struct expression *expr, struct range_list **rl, int *recurse_cnt)
{
	*rl = NULL;
	get_rl_internal(expr, RL_ABSOLUTE, recurse_cnt, rl);
	if (!*rl)
		*rl = alloc_whole_rl(get_type(expr));
	return 1;
}

int get_absolute_rl(struct expression *expr, struct range_list **rl)
{
	*rl = NULL;
	get_rl_helper(expr, RL_ABSOLUTE, rl);
	if (!*rl)
		*rl = alloc_whole_rl(get_type(expr));
	return 1;
}

int get_real_absolute_rl(struct expression *expr, struct range_list **rl)
{
	*rl = NULL;
	get_rl_helper(expr, RL_REAL_ABSOLUTE, rl);
	if (!*rl)
		*rl = alloc_whole_rl(get_type(expr));
	return 1;
}

int custom_get_absolute_rl(struct expression *expr,
			   struct range_list *(*fn)(struct expression *expr),
			   struct range_list **rl)
{
	int ret;

	*rl = NULL;
	custom_handle_variable = fn;
	ret = get_rl_helper(expr, RL_REAL_ABSOLUTE, rl);
	custom_handle_variable = NULL;
	return ret;
}

int get_implied_rl_var_sym(const char *var, struct symbol *sym, struct range_list **rl)
{
	struct smatch_state *state;

	state = get_state(SMATCH_EXTRA, var, sym);
	*rl = estate_rl(state);
	if (*rl)
		return 1;
	return 0;
}

int get_hard_max(struct expression *expr, sval_t *sval)
{
	struct range_list *rl;

	if (!get_rl_helper(expr, RL_HARD, &rl) || !rl)
		return 0;
	*sval = rl_max(rl);
	return 1;
}

int get_fuzzy_min(struct expression *expr, sval_t *sval)
{
	struct range_list *rl;
	sval_t tmp;

	if (!get_rl_helper(expr, RL_FUZZY, &rl) || !rl)
		return 0;
	tmp = rl_min(rl);
	if (sval_is_negative(tmp) && sval_is_min(tmp))
		return 0;
	*sval = tmp;
	return 1;
}

int get_fuzzy_max(struct expression *expr, sval_t *sval)
{
	struct range_list *rl;
	sval_t max;

	if (!get_rl_helper(expr, RL_FUZZY, &rl) || !rl)
		return 0;
	max = rl_max(rl);
	if (max.uvalue > INT_MAX - 10000)
		return 0;
	*sval = max;
	return 1;
}

int get_absolute_min(struct expression *expr, sval_t *sval)
{
	struct range_list *rl;
	struct symbol *type;

	type = get_type(expr);
	if (!type)
		type = &llong_ctype;  // FIXME: this is wrong but places assume get type can't fail.
	rl = NULL;
	get_rl_helper(expr, RL_REAL_ABSOLUTE, &rl);
	if (rl)
		*sval = rl_min(rl);
	else
		*sval = sval_type_min(type);

	if (sval_cmp(*sval, sval_type_min(type)) < 0)
		*sval = sval_type_min(type);
	return 1;
}

int get_absolute_max(struct expression *expr, sval_t *sval)
{
	struct range_list *rl;
	struct symbol *type;

	type = get_type(expr);
	if (!type)
		type = &llong_ctype;
	rl = NULL;
	get_rl_helper(expr, RL_REAL_ABSOLUTE, &rl);
	if (rl)
		*sval = rl_max(rl);
	else
		*sval = sval_type_max(type);

	if (sval_cmp(sval_type_max(type), *sval) < 0)
		*sval = sval_type_max(type);
	return 1;
}

int known_condition_true(struct expression *expr)
{
	sval_t tmp;

	if (!expr)
		return 0;

	if (__inline_fn && get_param_num(expr) >= 0) {
		if (get_implied_value(expr, &tmp) && tmp.value)
			return 1;
		return 0;
	}

	if (get_value(expr, &tmp) && tmp.value)
		return 1;

	return 0;
}

int known_condition_false(struct expression *expr)
{
	sval_t tmp;

	if (!expr)
		return 0;

	if (__inline_fn && get_param_num(expr) >= 0) {
		if (get_implied_value(expr, &tmp) && tmp.value == 0)
			return 1;
		return 0;
	}

	if (expr_is_zero(expr))
		return 1;

	return 0;
}

int implied_condition_true(struct expression *expr)
{
	sval_t tmp;

	if (!expr)
		return 0;

	if (known_condition_true(expr))
		return 1;
	if (get_implied_value(expr, &tmp) && tmp.value)
		return 1;

	if (expr->type == EXPR_POSTOP)
		return implied_condition_true(expr->unop);

	if (expr->type == EXPR_PREOP && expr->op == SPECIAL_DECREMENT)
		return implied_not_equal(expr->unop, 1);
	if (expr->type == EXPR_PREOP && expr->op == SPECIAL_INCREMENT)
		return implied_not_equal(expr->unop, -1);

	expr = strip_expr(expr);
	switch (expr->type) {
	case EXPR_COMPARE:
		if (do_comparison(expr) == 1)
			return 1;
		break;
	case EXPR_PREOP:
		if (expr->op == '!') {
			if (implied_condition_false(expr->unop))
				return 1;
			break;
		}
		break;
	default:
		if (implied_not_equal(expr, 0) == 1)
			return 1;
		break;
	}
	return 0;
}

int implied_condition_false(struct expression *expr)
{
	struct expression *tmp;
	sval_t sval;

	if (!expr)
		return 0;

	if (known_condition_false(expr))
		return 1;

	switch (expr->type) {
	case EXPR_COMPARE:
		if (do_comparison(expr) == 2)
			return 1;
	case EXPR_PREOP:
		if (expr->op == '!') {
			if (implied_condition_true(expr->unop))
				return 1;
			break;
		}
		tmp = strip_expr(expr);
		if (tmp != expr)
			return implied_condition_false(tmp);
		break;
	default:
		if (get_implied_value(expr, &sval) && sval.value == 0)
			return 1;
		break;
	}
	return 0;
}


