diff -urN sparse-0718/compile-i386.c sparse-current/compile-i386.c --- sparse-0718/compile-i386.c 2004-07-16 19:00:25.000000000 -0400 +++ sparse-current/compile-i386.c 2004-07-20 17:02:00.000000000 -0400 @@ -1051,30 +1051,25 @@ struct storage *right = x86_expression(expr->right); struct storage *new, *val; const char *opname = NULL; - unsigned int is_signed = type_is_signed(expr->left->ctype); /* FIXME */ unsigned int right_bits = expr->right->ctype->bit_size; switch(expr->op) { - case '<': - if (is_signed) opname = "setl"; - else opname = "setb"; - break; - case '>': - if (is_signed) opname = "setg"; - else opname = "seta"; - break; + case '<': opname = "setl"; break; + case '>': opname = "setg"; break; case SPECIAL_LTE: - if (is_signed) opname = "setle"; - else opname = "setbe"; - break; + opname = "setle"; break; case SPECIAL_GTE: - if (is_signed) opname = "setge"; - else opname = "setae"; - break; - + opname = "setge"; break; case SPECIAL_EQUAL: opname = "sete"; break; case SPECIAL_NOTEQUAL: opname = "setne"; break; - + case SPECIAL_UNSIGNED_LT: + opname = "setb"; break; + case SPECIAL_UNSIGNED_GT: + opname = "seta"; break; + case SPECIAL_UNSIGNED_LTE: + opname = "setb"; break; + case SPECIAL_UNSIGNED_GTE: + opname = "setae"; break; default: assert(0); break; diff -urN sparse-0718/evaluate.c sparse-current/evaluate.c --- sparse-0718/evaluate.c 2004-07-16 19:00:25.000000000 -0400 +++ sparse-current/evaluate.c 2004-07-21 18:18:21.676175064 -0400 @@ -108,9 +108,48 @@ return sym; } +static inline struct symbol *integer_promotion(struct symbol *type) +{ + unsigned long mod = type->ctype.modifiers; + int width; + + if (type->type == SYM_ENUM) + return &int_ctype; + else if (type->type == SYM_BITFIELD) { + mod = type->ctype.base_type->ctype.modifiers; + width = type->fieldwidth; + } else if (mod & (MOD_CHAR | MOD_SHORT)) + width = type->bit_size; + else + return type; + if (mod & MOD_UNSIGNED && width == bits_in_int) + return &uint_ctype; + return &int_ctype; +} + +/* + * integer part of usual arithmetic conversions: + * integer promotions are applied + * if left and right are identical, we are done + * if signedness is the same, convert one with lower rank + * unless unsigned argument has rank lower than signed one, convert the + * signed one. + * if signed argument is bigger than unsigned one, convert the unsigned. + * otherwise, convert signed. + * + * Leaving aside the integer promotions, that is equivalent to + * if identical, don't convert + * if left is bigger than right, convert right + * if right is bigger than left, convert right + * otherwise, if signedness is the same, convert one with lower rank + * otherwise convert the signed one. + */ static struct symbol *bigger_int_type(struct symbol *left, struct symbol *right) { - unsigned long lmod, rmod, mod; + unsigned long lmod, rmod; + + left = integer_promotion(left); + right = integer_promotion(right); if (left == right) goto left; @@ -121,21 +160,17 @@ if (right->bit_size > left->bit_size) goto right; - /* Same size integers - promote to unsigned, promote to long */ lmod = left->ctype.modifiers; rmod = right->ctype.modifiers; - mod = lmod | rmod; - if (mod == lmod) + if ((lmod ^ rmod) & MOD_UNSIGNED) { + if (lmod & MOD_UNSIGNED) + goto left; + } else if ((lmod & ~rmod) & (MOD_LONG | MOD_LONGLONG)) goto left; - if (mod == rmod) - goto right; - return ctype_integer(mod); right: left = right; left: - if (left->bit_size < bits_in_int) - left = &int_ctype; return left; } @@ -160,11 +195,20 @@ return type->type == SYM_PTR || type->type == SYM_ARRAY || type->type == SYM_FN; } -static int is_int_type(struct symbol *type) +static inline int is_int_type(struct symbol *type) { if (type->type == SYM_NODE) type = type->ctype.base_type; - return (type->type == SYM_BITFIELD) || type->ctype.base_type == &int_type; + return (type->type == SYM_ENUM) || + (type->type == SYM_BITFIELD) || + type->ctype.base_type == &int_type; +} + +static inline int is_float_type(struct symbol *type) +{ + if (type->type == SYM_NODE) + type = type->ctype.base_type; + return type->ctype.base_type == &fp_type; } static struct symbol *bad_expr_type(struct expression *expr) @@ -173,7 +217,43 @@ return NULL; } -static struct symbol * compatible_integer_binop(struct expression *expr, struct expression **lp, struct expression **rp) +static struct symbol *compatible_float_binop(struct expression **lp, struct expression **rp) +{ + struct expression *left = *lp, *right = *rp; + struct symbol *ltype = left->ctype, *rtype = right->ctype; + + if (ltype->type == SYM_NODE) + ltype = ltype->ctype.base_type; + if (rtype->type == SYM_NODE) + rtype = rtype->ctype.base_type; + if (is_float_type(ltype)) { + if (is_int_type(rtype)) + goto Left; + if (is_float_type(rtype)) { + unsigned long lmod = ltype->ctype.modifiers; + unsigned long rmod = rtype->ctype.modifiers; + lmod &= MOD_LONG | MOD_LONGLONG; + rmod &= MOD_LONG | MOD_LONGLONG; + if (lmod == rmod) + return ltype; + if (lmod & ~rmod) + goto Left; + else + goto Right; + } + return NULL; + } + if (!is_float_type(rtype) || !is_int_type(ltype)) + return NULL; +Right: + *lp = cast_to(left, rtype); + return rtype; +Left: + *rp = cast_to(right, ltype); + return ltype; +} + +static struct symbol *compatible_integer_binop(struct expression **lp, struct expression **rp) { struct expression *left = *lp, *right = *rp; struct symbol *ltype = left->ctype, *rtype = right->ctype; @@ -182,11 +262,6 @@ ltype = ltype->ctype.base_type; if (rtype->type == SYM_NODE) rtype = rtype->ctype.base_type; - /* Integer promotion? */ - if (ltype->type == SYM_ENUM || ltype->type == SYM_BITFIELD) - ltype = &int_ctype; - if (rtype->type == SYM_ENUM || rtype->type == SYM_BITFIELD) - rtype = &int_ctype; if (is_int_type(ltype) && is_int_type(rtype)) { struct symbol *ctype = bigger_int_type(ltype, rtype); @@ -200,9 +275,11 @@ return NULL; } -static struct symbol *evaluate_int_binop(struct expression *expr) +static struct symbol *evaluate_arith(struct expression *expr, int float_ok) { - struct symbol *ctype = compatible_integer_binop(expr, &expr->left, &expr->right); + struct symbol *ctype = compatible_integer_binop(&expr->left, &expr->right); + if (!ctype && float_ok) + ctype = compatible_float_binop(&expr->left, &expr->right); if (ctype) { expr->ctype = ctype; return ctype; @@ -221,17 +298,12 @@ { struct symbol *ctype; struct symbol *ptr_type = ptr->ctype; - struct symbol *i_type = i->ctype; int bit_size; - if (i_type->type == SYM_NODE) - i_type = i_type->ctype.base_type; if (ptr_type->type == SYM_NODE) ptr_type = ptr_type->ctype.base_type; - if (i_type->type == SYM_ENUM) - i_type = &int_ctype; - if (!is_int_type(i_type)) + if (!is_int_type(i->ctype)) return bad_expr_type(expr); ctype = ptr->ctype; @@ -287,8 +359,7 @@ if (is_ptr_type(rtype)) return evaluate_ptr_add(expr, right, left); - // FIXME! FP promotion - return evaluate_int_binop(expr); + return evaluate_arith(expr, 1); } #define MOD_SIZE (MOD_CHAR | MOD_SHORT | MOD_LONG | MOD_LONGLONG) @@ -519,15 +590,15 @@ if (is_ptr_type(ltype)) return evaluate_ptr_sub(expr, left, right); - // FIXME! FP promotion - return evaluate_int_binop(expr); + return evaluate_arith(expr, 1); } #define is_safe_type(type) ((type)->ctype.modifiers & MOD_SAFE) -static struct symbol *evaluate_conditional(struct expression *expr) +static struct symbol *evaluate_conditional(struct expression **p) { struct symbol *ctype; + struct expression *expr = *p; if (!expr) return NULL; @@ -536,27 +607,64 @@ warn(expr->pos, "assignment expression in conditional"); ctype = evaluate_expression(expr); - if (ctype && is_safe_type(ctype)) - warn(expr->pos, "testing a 'safe expression'"); + if (ctype) { + if (is_safe_type(ctype)) + warn(expr->pos, "testing a 'safe expression'"); + if (is_float_type(ctype)) { + struct expression *comp; + /* + * It's easier to handle here, rather than deal with + * FP all over the place. Floating point in boolean + * context is rare enough (and very often wrong), + * so price of explicit comparison with appropriate + * FP zero is not too high. And it simplifies things + * elsewhere. + */ + comp = alloc_expression(expr->pos, EXPR_BINOP); + comp->op = SPECIAL_NOTEQUAL; + comp->left = expr; + comp->right = alloc_expression(expr->pos, EXPR_FVALUE); + comp->right->ctype = comp->left->ctype; + comp->right->fvalue = 0; + ctype = comp->ctype = &bool_ctype; + *p = comp; + } + } return ctype; } static struct symbol *evaluate_logical(struct expression *expr) { - if (!evaluate_conditional(expr->left)) + if (!evaluate_conditional(&expr->left)) return NULL; - if (!evaluate_conditional(expr->right)) + if (!evaluate_conditional(&expr->right)) return NULL; expr->ctype = &bool_ctype; return &bool_ctype; } -static struct symbol *evaluate_arithmetic(struct expression *expr) +static struct symbol *evaluate_shift(struct expression *expr) { - // FIXME! Floating-point promotion! - return evaluate_int_binop(expr); + struct expression *left = expr->left, *right = expr->right; + struct symbol *ltype = left->ctype, *rtype = right->ctype; + + if (ltype->type == SYM_NODE) + ltype = ltype->ctype.base_type; + if (rtype->type == SYM_NODE) + rtype = rtype->ctype.base_type; + if (is_int_type(ltype) && is_int_type(rtype)) { + struct symbol *ctype = integer_promotion(ltype); + if (ltype->bit_size != ctype->bit_size) + expr->left = cast_to(expr->left, ctype); + expr->ctype = ctype; + ctype = integer_promotion(rtype); + if (rtype->bit_size != ctype->bit_size) + expr->right = cast_to(expr->right, ctype); + return expr->ctype; + } + return bad_expr_type(expr); } static struct symbol *evaluate_binop(struct expression *expr) @@ -571,14 +679,17 @@ return evaluate_sub(expr); // Arithmetic operations can take fp and int - case '*': case '/': case '%': - return evaluate_arithmetic(expr); + case '*': case '/': + return evaluate_arith(expr, 1); + + // shifts do integer promotions, but that's it. + case SPECIAL_LEFTSHIFT: case SPECIAL_RIGHTSHIFT: + return evaluate_shift(expr); - // The rest are integer operations (bitops) - // SPECIAL_LEFTSHIFT, SPECIAL_RIGHTSHIFT - // '&', '^', '|' + // The rest are integer operations + // '%', '&', '^', '|' default: - return evaluate_int_binop(expr); + return evaluate_arith(expr, 0); } } @@ -588,6 +699,19 @@ return expr->ctype; } +static int modify_for_unsigned(int op) +{ + if (op == '<') + op = SPECIAL_UNSIGNED_LT; + else if (op == '>') + op = SPECIAL_UNSIGNED_GT; + else if (op == SPECIAL_LTE) + op = SPECIAL_UNSIGNED_LTE; + else if (op == SPECIAL_GTE) + op = SPECIAL_UNSIGNED_GTE; + return op; +} + static struct symbol *evaluate_compare(struct expression *expr) { struct expression *left = expr->left, *right = expr->right; @@ -610,29 +734,18 @@ return &bool_ctype; } - ctype = compatible_integer_binop(expr, &expr->left, &expr->right); + ctype = compatible_integer_binop(&expr->left, &expr->right); if (ctype) { + if (ctype->ctype.modifiers & MOD_UNSIGNED) + expr->op = modify_for_unsigned(expr->op); expr->ctype = &bool_ctype; return &bool_ctype; } + ctype = compatible_float_binop(&expr->left, &expr->right); return bad_expr_type(expr); } -static int compatible_integer_types(struct symbol *ltype, struct symbol *rtype) -{ - /* Integer promotion? */ - if (ltype->type == SYM_NODE) - ltype = ltype->ctype.base_type; - if (rtype->type == SYM_NODE) - rtype = rtype->ctype.base_type; - if (ltype->type == SYM_ENUM || ltype->type == SYM_BITFIELD) - ltype = &int_ctype; - if (rtype->type == SYM_ENUM || rtype->type == SYM_BITFIELD) - rtype = &int_ctype; - return (is_int_type(ltype) && is_int_type(rtype)); -} - /* * FIXME!! This should do casts, array degeneration etc.. */ @@ -679,17 +792,22 @@ ctype = ltype; typediff = type_difference(ltype, rtype, MOD_IGN, MOD_IGN); - if (typediff) { - ctype = compatible_integer_binop(expr, &true, &expr->cond_false); - if (!ctype) { - ctype = compatible_ptr_type(true, expr->cond_false); - if (!ctype) { - warn(expr->pos, "incompatible types in conditional expression (%s)", typediff); - return NULL; - } - } - } + if (!typediff) + goto out; + ctype = compatible_integer_binop(&true, &expr->cond_false); + if (ctype) + goto out; + ctype = compatible_ptr_type(true, expr->cond_false); + if (ctype) + goto out; + ctype = compatible_float_binop(&true, &expr->cond_false); + if (ctype) + goto out; + warn(expr->pos, "incompatible types in conditional expression (%s)", typediff); + return NULL; + +out: expr->ctype = ctype; return ctype; } @@ -706,10 +824,22 @@ if (!typediff) return 1; - if (compatible_integer_types(target, source)) { - if (target->bit_size != source->bit_size) - *rp = cast_to(*rp, target); - return 1; + if (is_int_type(target)) { + if (is_int_type(source)) { + if (target->bit_size != source->bit_size) + goto Cast; + return 1; + } + if (is_float_type(source)) + goto Cast; + } else if (is_float_type(target)) { + if (is_int_type(source)) + goto Cast; + if (is_float_type(source)) { + if (target->bit_size != source->bit_size) + goto Cast; + return 1; + } } /* Pointer destination? */ @@ -747,6 +877,9 @@ info(expr->pos, " expected %s", show_typename(target)); info(expr->pos, " got %s", show_typename(source)); return 0; +Cast: + *rp = cast_to(*rp, target); + return 1; } /* @@ -1022,16 +1155,39 @@ return ctype; } +static struct symbol *evaluate_sign(struct expression *expr) +{ + struct expression *arg = expr->unop; + struct symbol *ctype = arg->ctype; + if (is_int_type(ctype)) { + struct symbol *rtype = rtype = integer_promotion(ctype); + if (rtype->bit_size != ctype->bit_size) + expr->unop = cast_to(arg, rtype); + ctype = rtype; + } else if (is_float_type(ctype)) { + /* no conversions needed */ + } else { + return bad_expr_type(expr); + } + if (expr->op == '+') + *expr = *arg; + expr->ctype = ctype; + return ctype; +} + static struct symbol *evaluate_preop(struct expression *expr) { struct symbol *ctype = expr->unop->ctype; switch (expr->op) { case '(': - case '+': *expr = *expr->unop; return ctype; + case '-': + case '+': + return evaluate_sign(expr); + case '*': return evaluate_dereference(expr); @@ -1049,6 +1205,15 @@ case '!': if (is_safe_type(ctype)) warn(expr->pos, "testing a 'safe expression'"); + if (is_float_type(ctype)) { + struct expression *arg = expr->unop; + expr->type = EXPR_BINOP; + expr->op = SPECIAL_EQUAL; + expr->left = arg; + expr->right = alloc_expression(expr->pos, EXPR_FVALUE); + expr->right->ctype = ctype; + expr->right->fvalue = 0; + } ctype = &bool_ctype; break; @@ -1581,6 +1746,7 @@ switch (expr->type) { case EXPR_VALUE: + case EXPR_FVALUE: warn(expr->pos, "value expression without a type"); return NULL; case EXPR_STRING: @@ -1635,7 +1801,7 @@ warn(expr->pos, "bitfield generated by parser"); return NULL; case EXPR_CONDITIONAL: - if (!evaluate_conditional(expr->conditional)) + if (!evaluate_conditional(&expr->conditional)) return NULL; if (!evaluate_expression(expr->cond_false)) return NULL; @@ -1749,13 +1915,12 @@ static void evaluate_if_statement(struct statement *stmt) { - struct expression *expr = stmt->if_conditional; struct symbol *ctype; - if (!expr) + if (!stmt->if_conditional) return; - ctype = evaluate_conditional(expr); + ctype = evaluate_conditional(&stmt->if_conditional); if (!ctype) return; @@ -1801,8 +1966,8 @@ evaluate_if_statement(stmt); return NULL; case STMT_ITERATOR: - evaluate_conditional(stmt->iterator_pre_condition); - evaluate_conditional(stmt->iterator_post_condition); + evaluate_conditional(&stmt->iterator_pre_condition); + evaluate_conditional(&stmt->iterator_post_condition); evaluate_statement(stmt->iterator_pre_statement); evaluate_statement(stmt->iterator_statement); evaluate_statement(stmt->iterator_post_statement); diff -urN sparse-0718/expand.c sparse-current/expand.c --- sparse-0718/expand.c 2004-07-16 19:00:25.000000000 -0400 +++ sparse-current/expand.c 2004-07-20 17:51:38.000000000 -0400 @@ -43,19 +43,32 @@ } } +static long long get_longlong(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(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, ormask, andmask; - int is_signed; + long long value, mask; - // FIXME! We don't handle FP casts of constant values yet - if (newtype->ctype.base_type == &fp_type) - return; - if (oldtype->ctype.base_type == &fp_type) - return; + if (newtype->ctype.base_type == &fp_type || + oldtype->ctype.base_type == &fp_type) + goto Float; // For pointers and integers, we can just move the value around expr->type = EXPR_VALUE; @@ -65,21 +78,34 @@ } // expand it to the full "long long" value - is_signed = !(oldtype->ctype.modifiers & MOD_UNSIGNED); - mask = 1ULL << (old_size-1); - value = old->value; - if (!(value & mask)) - is_signed = 0; - andmask = mask | (mask-1); - ormask = ~andmask; - if (!is_signed) - ormask = 0; - value = (value & andmask) | ormask; + value = get_longlong(old); +Int: // Truncate it to the new size mask = 1ULL << (new_size-1); mask = mask | (mask-1); expr->value = value & mask; + return; + +Float: + if (newtype->ctype.base_type != &fp_type) { + value = (long long)expr->fvalue; + expr->type = EXPR_VALUE; + goto Int; + } + + if (oldtype->ctype.base_type != &fp_type) + expr->fvalue = (long double)get_longlong(old); + else + expr->fvalue = old->value; + + if (!(newtype->ctype.modifiers & MOD_LONGLONG)) { + 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(struct expression *expr, struct symbol *ctype, unsigned int count) @@ -95,7 +121,7 @@ * CAREFUL! We need to get the size and sign of the * result right! */ -static void simplify_int_binop(struct expression *expr, struct symbol *ctype) +static int simplify_int_binop(struct expression *expr, struct symbol *ctype) { struct expression *left = expr->left, *right = expr->right; unsigned long long v, l, r, mask; @@ -103,7 +129,7 @@ int is_signed, shift; if (left->type != EXPR_VALUE || right->type != EXPR_VALUE) - return; + return 0; l = left->value; r = right->value; is_signed = !(ctype->ctype.modifiers & MOD_UNSIGNED); mask = 1ULL << (ctype->bit_size-1); @@ -120,28 +146,125 @@ case '|': v = l | r; s = v; break; case '^': v = l ^ r; s = v; break; case '*': v = l * r; s = sl * sr; break; - case '/': if (!r) return; v = l / r; s = sl / sr; break; - case '%': if (!r) return; v = l % r; s = sl % sr; break; + case '/': if (!r) goto Div; v = l / r; s = sl / sr; break; + case '%': if (!r) goto Div; v = l % r; s = sl % sr; break; case SPECIAL_LEFTSHIFT: shift = check_shift_count(expr, ctype, r); v = l << shift; s = v; break; case SPECIAL_RIGHTSHIFT:shift = check_shift_count(expr, ctype, r); v = l >> shift; s = sl >> shift; break; - case '<': v = l < r; s = sl < sr; break; - case '>': v = l > r; s = sl > sr; break; - case SPECIAL_LTE: v = l <= r; s = sl <= sr; break; - case SPECIAL_GTE: v = l >= r; s = sl >= sr; break; - case SPECIAL_EQUAL: v = l == r; s = v; break; - case SPECIAL_NOTEQUAL: v = l != r; s = v; break; - default: return; + default: return 0; } if (is_signed) v = s; mask = mask | (mask-1); expr->value = v & mask; expr->type = EXPR_VALUE; + return 1; +Div: + warn(expr->pos, "division by zero"); + return 0; +} + +static int simplify_cmp_binop(struct expression *expr, struct symbol *ctype) +{ + struct expression *left = expr->left, *right = expr->right; + unsigned long long l, r, mask; + signed long long sl, sr; + + if (left->type != EXPR_VALUE || right->type != EXPR_VALUE) + return 0; + l = left->value; r = right->value; + mask = 1ULL << (ctype->bit_size-1); + sl = l; sr = r; + if (sl & mask) + sl |= ~(mask-1); + if (sr & mask) + sr |= ~(mask-1); + switch (expr->op) { + case '<': expr->value = sl < sr; break; + case '>': expr->value = sl > sr; break; + case SPECIAL_LTE: expr->value = sl <= sr; break; + case SPECIAL_GTE: expr->value = sl >= sr; break; + case SPECIAL_EQUAL: expr->value = l == r; break; + case SPECIAL_NOTEQUAL: expr->value = l != r; break; + case SPECIAL_UNSIGNED_LT:expr->value = l < r; break; + case SPECIAL_UNSIGNED_GT:expr->value = l > r; break; + case SPECIAL_UNSIGNED_LTE:expr->value = l <= r; break; + case SPECIAL_UNSIGNED_GTE:expr->value = l >= r; break; + } + expr->type = EXPR_VALUE; + return 1; +} + +static int simplify_float_binop(struct expression *expr) +{ + struct expression *left = expr->left, *right = expr->right; + unsigned long mod = expr->ctype->ctype.modifiers; + long double l = left->fvalue; + long double r = right->fvalue; + long double res; + + if (left->type != EXPR_FVALUE || right->type != EXPR_FVALUE) + return 0; + if (mod & MOD_LONGLONG) { + switch (expr->op) { + case '+': res = l + r; break; + case '-': res = l - r; break; + case '*': res = l * r; break; + case '/': if (!r) goto Div; + res = l / r; break; + default: return 0; + } + } else if (mod & MOD_LONG) { + switch (expr->op) { + case '+': res = (double) l + (double) r; break; + case '-': res = (double) l - (double) r; break; + case '*': res = (double) l * (double) r; break; + case '/': if (!r) goto Div; + res = (double) l / (double) r; break; + default: return 0; + } + } else { + switch (expr->op) { + case '+': res = (float)l + (float)r; break; + case '-': res = (float)l - (float)r; break; + case '*': res = (float)l * (float)r; break; + case '/': if (!r) goto Div; + res = (float)l / (float)r; break; + default: return 0; + } + } + expr->type = EXPR_FVALUE; + expr->fvalue = res; + return 1; +Div: + warn(expr->pos, "division by zero"); + return 0; +} + +static int simplify_float_cmp(struct expression *expr, struct symbol *ctype) +{ + struct expression *left = expr->left, *right = expr->right; + long double l = left->fvalue, r = right->fvalue; + + if (left->type != EXPR_FVALUE || right->type != EXPR_FVALUE) + return 0; + + switch (expr->op) { + case '<': expr->value = l < r; break; + case '>': expr->value = l > r; break; + case SPECIAL_LTE: expr->value = l <= r; break; + case SPECIAL_GTE: expr->value = l >= r; break; + case SPECIAL_EQUAL: expr->value = l == r; break; + case SPECIAL_NOTEQUAL: expr->value = l != r; break; + } + expr->type = EXPR_VALUE; + return 1; } -static void expand_int_binop(struct expression *expr) +static void expand_binop(struct expression *expr) { - simplify_int_binop(expr, expr->ctype); + if (simplify_int_binop(expr, expr->ctype)) + return; + simplify_float_binop(expr); } static void expand_logical(struct expression *expr) @@ -175,18 +298,13 @@ * otherwise we would have short-circuited it.. */ expr->type = EXPR_VALUE; - expr->value = right->value; + expr->value = right->value != 0; } } -static void expand_binop(struct expression *expr) -{ - expand_int_binop(expr); -} - static void expand_comma(struct expression *expr) { - if (expr->left->type == EXPR_VALUE) + if (expr->left->type == EXPR_VALUE || expr->left->type == EXPR_FVALUE) *expr = *expr->right; } @@ -222,7 +340,9 @@ expr->value = compare_types(op, left->symbol, right->symbol); return; } - simplify_int_binop(expr, expr->ctype); + if (simplify_cmp_binop(expr, left->ctype)) + return; + simplify_float_cmp(expr, left->ctype); } static void expand_conditional(struct expression *expr) @@ -274,31 +394,53 @@ if (value->type == EXPR_VALUE) { expr->type = EXPR_VALUE; expr->value = value->value; + } else if (value->type == EXPR_FVALUE) { + expr->type = EXPR_FVALUE; + expr->fvalue = value->fvalue; } } } } } -static void simplify_preop(struct expression *expr) +static int simplify_preop(struct expression *expr) { struct expression *op = expr->unop; unsigned long long v, mask; if (op->type != EXPR_VALUE) - return; + return 0; v = op->value; switch (expr->op) { case '+': break; case '-': v = -v; break; case '!': v = !v; break; case '~': v = ~v; break; - default: return; + default: return 0; } mask = 1ULL << (expr->ctype->bit_size-1); mask = mask | (mask-1); expr->value = v & mask; expr->type = EXPR_VALUE; + return 1; +} + +static int simplify_float_preop(struct expression *expr) +{ + struct expression *op = expr->unop; + long double v; + + if (op->type != EXPR_FVALUE) + return 0; + v = op->fvalue; + switch (expr->op) { + case '+': break; + case '-': v = -v; break; + default: return 0; + } + expr->fvalue = v; + expr->type = EXPR_FVALUE; + return 1; } /* @@ -331,7 +473,9 @@ default: break; } - simplify_preop(expr); + if (simplify_preop(expr)) + return; + simplify_float_preop(expr); } static void expand_arguments(struct expression_list *head) @@ -350,7 +494,7 @@ expand_expression(target); /* Simplify normal integer casts.. */ - if (target->type == EXPR_VALUE) + if (target->type == EXPR_VALUE || target->type == EXPR_FVALUE) cast_value(expr, expr->ctype, target, target->ctype); } @@ -402,7 +546,7 @@ switch (expr->type) { case EXPR_VALUE: - return; + case EXPR_FVALUE: case EXPR_STRING: return; case EXPR_TYPE: diff -urN sparse-0718/expression.c sparse-current/expression.c --- sparse-0718/expression.c 2004-07-16 19:00:25.000000000 -0400 +++ sparse-current/expression.c 2004-07-20 17:46:44.000000000 -0400 @@ -8,6 +8,7 @@ * * This is the expression parsing part of parsing C. */ +#define _ISOC99_SOURCE #include #include #include @@ -90,18 +91,6 @@ return next; } -static void get_fp_value(struct expression *expr, struct token *token) -{ - static int fp_warned; - - expr->ctype = &double_ctype; - expr->value = 0; - if (!fp_warned) { - warn(token->pos, "FP values not yet implemented"); - fp_warned = 1; - } -} - #ifndef ULLONG_MAX #define ULLONG_MAX (~0ULL) #endif @@ -119,7 +108,7 @@ errno = 0; value = strtoull(str, &end, 0); if (end == str) - goto Enoint; + goto Float; if (value == ULLONG_MAX && errno == ERANGE) overflow = 1; while (1) { @@ -136,7 +125,7 @@ end++; } } else - goto Enoint; + goto Float; if (modifiers & added) goto Enoint; modifiers |= added; @@ -203,8 +192,29 @@ Eoverflow: error(expr->pos, "constant %s is too big even for unsigned long long", show_token(token)); + return; +Float: + expr->fvalue = strtold(str, &end); + if (str == end) + goto Enoint; + + if (*end && end[1]) + goto Enoint; + + if (*end == 'f' || *end == 'F') + expr->ctype = &float_ctype; + else if (*end == 'l' || *end == 'L') + expr->ctype = &ldouble_ctype; + else if (!*end) + expr->ctype = &double_ctype; + else + goto Enoint; + + expr->type = EXPR_FVALUE; + return; + Enoint: - get_fp_value(expr, token); + error(expr->pos, "constant %s is not a valid number", show_token(token)); } struct token *primary_expression(struct token *token, struct expression **tree) diff -urN sparse-0718/expression.h sparse-current/expression.h --- sparse-0718/expression.h 2004-07-16 19:00:25.000000000 -0400 +++ sparse-current/expression.h 2004-07-20 15:55:56.000000000 -0400 @@ -38,6 +38,7 @@ EXPR_IDENTIFIER, // identifier in initializer EXPR_INDEX, // index in initializer EXPR_POS, // position in initializer + EXPR_FVALUE, }; struct expression { @@ -49,6 +50,9 @@ // EXPR_VALUE unsigned long long value; + // EXPR_FVALUE + long double fvalue; + // EXPR_STRING struct string *string; diff -urN sparse-0718/inline.c sparse-current/inline.c --- sparse-0718/inline.c 2004-07-16 19:00:26.000000000 -0400 +++ sparse-current/inline.c 2004-07-20 14:42:28.000000000 -0400 @@ -77,6 +77,7 @@ /* Atomics, never change, just return the expression directly */ case EXPR_VALUE: case EXPR_STRING: + case EXPR_FVALUE: break; /* Unops: check if the subexpression is unique */ @@ -109,8 +110,8 @@ /* Dereference */ case EXPR_DEREF: { struct expression *deref = copy_expression(expr->deref); - if (deref == expr->deref) - break; +// if (deref == expr->deref) +// break; expr = dup_expression(expr); expr->deref = deref; break; @@ -432,7 +433,7 @@ NEXT_PTR_LIST(name); } END_FOR_EACH_PTR; FINISH_PTR_LIST(name); - + copy_statement(fn->stmt, stmt); unset_replace_list(fn_symbol_list); diff -urN sparse-0718/linearize.c sparse-current/linearize.c --- sparse-0718/linearize.c 2004-05-31 20:00:23.000000000 -0400 +++ sparse-current/linearize.c 2004-07-20 16:57:54.000000000 -0400 @@ -94,6 +94,10 @@ printf("\t%%r%d <- %lld\n", insn->target->nr, expr->value); break; + case EXPR_FVALUE: + printf("\t%%r%d <- %Lf\n", + insn->target->nr, expr->fvalue); + break; case EXPR_STRING: printf("\t%%r%d <- %s\n", insn->target->nr, show_string(expr->string)); @@ -177,6 +181,10 @@ [OP_SET_GE - OP_BINCMP] = "setge", [OP_SET_LT - OP_BINCMP] = "setlt", [OP_SET_GT - OP_BINCMP] = "setgt", + [OP_SET_BE - OP_BINCMP] = "setbe", + [OP_SET_AE - OP_BINCMP] = "setae", + [OP_SET_A - OP_BINCMP] = "seta", + [OP_SET_B - OP_BINCMP] = "setb", }; printf("\t%%r%d <- %s %%r%d, %%r%d\n", insn->target->nr, @@ -407,6 +415,7 @@ return linearize_load_gen(ep, expr, addr); } +/* FIXME: FP */ static pseudo_t linearize_inc_dec(struct entrypoint *ep, struct expression *expr, int postop) { pseudo_t addr = linearize_address_gen(ep, expr->unop); @@ -602,6 +611,10 @@ [SPECIAL_NOTEQUAL] = OP_SET_NE, [SPECIAL_GTE] = OP_SET_GE, [SPECIAL_LTE] = OP_SET_LE, + [SPECIAL_UNSIGNED_LT] = OP_SET_B, + [SPECIAL_UNSIGNED_GT] = OP_SET_A, + [SPECIAL_UNSIGNED_LTE] = OP_SET_BE, + [SPECIAL_UNSIGNED_GTE] = OP_SET_AE, }; pseudo_t src1 = linearize_expression(ep, expr->left); @@ -623,6 +636,10 @@ case EXPR_VALUE: add_goto(ep, expr->value ? bb_true : bb_false); return VOID; + + case EXPR_FVALUE: + add_goto(ep, expr->fvalue ? bb_true : bb_false); + return VOID; case EXPR_LOGICAL: linearize_logical_branch(ep, expr, bb_true, bb_false); @@ -685,7 +702,7 @@ return VOID; switch (expr->type) { - case EXPR_VALUE: case EXPR_STRING: case EXPR_SYMBOL: + case EXPR_VALUE: case EXPR_STRING: case EXPR_SYMBOL: case EXPR_FVALUE: return add_setval(ep, expr->ctype, expr); case EXPR_STATEMENT: diff -urN sparse-0718/linearize.h sparse-current/linearize.h --- sparse-0718/linearize.h 2004-05-24 20:00:19.000000000 -0400 +++ sparse-current/linearize.h 2004-07-20 10:26:16.000000000 -0400 @@ -101,7 +101,11 @@ OP_SET_GE, OP_SET_LT, OP_SET_GT, - OP_BINCMP_END = OP_SET_GT, + OP_SET_B, + OP_SET_A, + OP_SET_BE, + OP_SET_AE, + OP_BINCMP_END = OP_SET_AE, /* Uni */ OP_NOT, diff -urN sparse-0718/show-parse.c sparse-current/show-parse.c --- sparse-0718/show-parse.c 2004-07-16 19:00:26.000000000 -0400 +++ sparse-current/show-parse.c 2004-07-20 16:03:55.000000000 -0400 @@ -842,6 +842,15 @@ return new; } +static int show_fvalue(struct expression *expr) +{ + int new = new_pseudo(); + long double value = expr->fvalue; + + printf("\tmovf.%d\t\tv%d,$%Lf\n", expr->ctype->bit_size, new, value); + return new; +} + static int show_string_expr(struct expression *expr) { int new = new_pseudo(); @@ -969,6 +978,8 @@ return show_cast_expr(expr); case EXPR_VALUE: return show_value(expr); + case EXPR_FVALUE: + return show_fvalue(expr); case EXPR_STRING: return show_string_expr(expr); case EXPR_BITFIELD: diff -urN sparse-0718/symbol.c sparse-current/symbol.c --- sparse-0718/symbol.c 2004-06-06 19:00:23.000000000 -0400 +++ sparse-current/symbol.c 2004-07-20 20:57:20.000000000 -0400 @@ -149,7 +149,7 @@ return; examine_symbol_type(base_type); bit_size = base_type->bit_size * get_expression_value(sym->array_size); - if (!sym->array_size) + if (!sym->array_size || sym->array_size->type != EXPR_VALUE) bit_size = -1; alignment = base_type->ctype.alignment; if (!sym->ctype.alignment) @@ -345,7 +345,7 @@ int value = 1; FOR_EACH_PTR (arglist, arg) { - if (arg->type != EXPR_VALUE) + if (arg->type != EXPR_VALUE && arg->type != EXPR_VALUE) value = 0; } END_FOR_EACH_PTR; diff -urN sparse-0718/token.h sparse-current/token.h --- sparse-0718/token.h 2004-07-16 19:00:26.000000000 -0400 +++ sparse-current/token.h 2004-07-20 09:59:42.000000000 -0400 @@ -109,7 +109,11 @@ SPECIAL_OR_ASSIGN, SPECIAL_XOR_ASSIGN, SPECIAL_HASHHASH, - SPECIAL_ARG_SEPARATOR + SPECIAL_ARG_SEPARATOR, + SPECIAL_UNSIGNED_LT, + SPECIAL_UNSIGNED_GT, + SPECIAL_UNSIGNED_LTE, + SPECIAL_UNSIGNED_GTE, }; struct string {