C-sparse

 view release on metacpan or  search on metacpan

src/sparse-0.4.4/expand.c  view on Meta::CPAN

#include <limits.h>

#include "lib.h"
#include "allocate.h"
#include "parse.h"
#include "token.h"
#include "symbol.h"
#include "target.h"
#include "expression.h"

/* Random cost numbers */
#define SIDE_EFFECTS 10000	/* The expression has side effects */
#define UNSAFE 100		/* The expression may be "infinitely costly" due to exceptions */
#define SELECT_COST 20		/* Cut-off for turning a conditional into a select */
#define BRANCH_COST 10		/* Cost of a conditional branch */

static int expand_expression(SCTX_ struct expression *);
static int expand_statement(SCTX_ struct statement *);
#ifndef DO_CTX
static int conservative;
#endif

static int expand_symbol_expression(SCTX_ struct expression *expr)
{
	struct symbol *sym = expr->symbol;

	if (sym == &sctxp zero_int) {
		if (sctxp Wundef)
			warning(sctx_ expr->pos->pos, "undefined preprocessor identifier '%s'", show_ident(sctx_ expr->symbol_name));
		expr->type = EXPR_VALUE;
		expr->value = 0;
		expr->taint = 0;
		return 0;
	}
	/* The cost of a symbol expression is lower for on-stack symbols */
	return (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN)) ? 2 : 1;
}

static long long get_longlong(SCTX_ struct expression *expr)
{
	int no_expand = expr->ctype->ctype.modifiers & MOD_UNSIGNED;
	long long mask = 1ULL << (expr->ctype->bit_size - 1);
	long long value = expr->value;
	long long ormask, andmask;

	if (!(value & mask))
		no_expand = 1;
	andmask = mask | (mask-1);
	ormask = ~andmask;
	if (no_expand)
		ormask = 0;
	return (value & andmask) | ormask;
}

void cast_value(SCTX_ struct expression *expr, struct symbol *newtype,
		struct expression *old, struct symbol *oldtype)
{
	int old_size = oldtype->bit_size;
	int new_size = newtype->bit_size;
	long long value, mask, signmask;
	long long oldmask, oldsignmask, dropped;

	if (newtype->ctype.base_type == &sctxp fp_type ||
	    oldtype->ctype.base_type == &sctxp fp_type)
		goto Float;

	// For pointers and integers, we can just move the value around
	expr->type = EXPR_VALUE;
	expr->taint = old->taint;
	if (old_size == new_size) {
		expr->value = old->value;
		return;
	}

	// expand it to the full "long long" value
	value = get_longlong(sctx_ old);

Int:
	// _Bool requires a zero test rather than truncation.
	if (is_bool_type(sctx_ newtype)) {
		expr->value = !!value;
		if (!sctxp conservative && value != 0 && value != 1)
			warning(sctx_ old->pos->pos, "odd constant _Bool cast (%llx becomes 1)", value);
		return;
	}

	// Truncate it to the new size
	signmask = 1ULL << (new_size-1);
	mask = signmask | (signmask-1);
	expr->value = value & mask;

	// Stop here unless checking for truncation
	if (!sctxp Wcast_truncate || sctxp conservative)
		return;
	
	// Check if we dropped any bits..
	oldsignmask = 1ULL << (old_size-1);
	oldmask = oldsignmask | (oldsignmask-1);
	dropped = oldmask & ~mask;

	// OK if the bits were (and still are) purely sign bits
	if (value & dropped) {
		if (!(value & oldsignmask) || !(value & signmask) || (value & dropped) != dropped)
			warning(sctx_ old->pos->pos, "cast truncates bits from constant value (%llx becomes %llx)",
				value & oldmask,
				value & mask);
	}
	return;

Float:
	if (!is_float_type(sctx_ newtype)) {
		value = (long long)old->fvalue;
		expr->type = EXPR_VALUE;
		expr->taint = 0;
		goto Int;
	}

	if (!is_float_type(sctx_ oldtype))
		expr->fvalue = (long double)get_longlong(sctx_ old);
	else
		expr->fvalue = old->fvalue;

	if (!(newtype->ctype.modifiers & MOD_LONGLONG) && \
	    !(newtype->ctype.modifiers & MOD_LONGLONGLONG)) {
		if ((newtype->ctype.modifiers & MOD_LONG))
			expr->fvalue = (double)expr->fvalue;
		else
			expr->fvalue = (float)expr->fvalue;
	}
	expr->type = EXPR_FVALUE;
}

static int check_shift_count(SCTX_ struct expression *expr, struct symbol *ctype, unsigned int count)
{
	warning(sctx_ expr->pos->pos, "shift too big (%u) for type %s", count, show_typename(sctx_ ctype));
	count &= ctype->bit_size-1;
	return count;
}

/*
 * CAREFUL! We need to get the size and sign of the
 * result right!
 */
#define CONVERT(op,s)	(((op)<<1)+(s))
#define SIGNED(op)	CONVERT(op, 1)
#define UNSIGNED(op)	CONVERT(op, 0)
static int simplify_int_binop(SCTX_ struct expression *expr, struct symbol *ctype)
{
	struct expression *left = expr->left, *right = expr->right;
	unsigned long long v, l, r, mask;
	signed long long sl, sr;
	int is_signed;

	if (right->type != EXPR_VALUE)
		return 0;
	r = right->value;
	if (expr->op == SPECIAL_LEFTSHIFT || expr->op == SPECIAL_RIGHTSHIFT) {
		if (r >= ctype->bit_size) {
			if (sctxp conservative)
				return 0;
			r = check_shift_count(sctx_ expr, ctype, r);
			right->value = r;
		}



( run in 2.656 seconds using v1.01-cache-2.11-cpan-71847e10f99 )