fix semantic bugs, do default promotion for call arguments, implement some arithmetic...
authorMatthias Braun <matze@braunis.de>
Wed, 14 Nov 2007 16:14:43 +0000 (16:14 +0000)
committerMatthias Braun <matze@braunis.de>
Wed, 14 Nov 2007 16:14:43 +0000 (16:14 +0000)
[r18391]

TODO
ast2firm.c
parser.c
type_t.h

diff --git a/TODO b/TODO
index ab1a85d..8a40074 100644 (file)
--- a/TODO
+++ b/TODO
@@ -11,6 +11,7 @@ Parser:
 - proper handling of function pointer types
 - outermost typequalifiers can differ between function declarations and
   implementations...
+- fix semantic to ignore type qualifiers (const double is the same as double)
 
 ast2firm:
 - output source file positions for panics...
index a5e79fa..4e242ad 100644 (file)
@@ -911,13 +911,30 @@ static ir_node *create_arithmetic_binop(const binary_expression_t *expression,
        dbg_info *dbgi  = get_dbg_info(&expression->expression.source_position);
        ir_node  *left  = expression_to_firm(expression->left);
        ir_node  *right = expression_to_firm(expression->right);
-       type_t   *type  = expression->expression.datatype;
+       type_t   *type  = expression->right->datatype;
+       /* be careful with the modes, because in asithmetic assign nodes only
+        * the right operand has the mode of the arithmetic alread */
        ir_mode  *mode  = get_ir_mode(type);
+       left            = create_conv(dbgi, left, mode);
        ir_node  *res   = func(dbgi, left, right, mode);
 
        return res;
 }
 
+static ir_node *create_arithmetic_assign_binop(
+               const binary_expression_t *expression, create_arithmetic_func func)
+{
+       dbg_info *dbgi  = get_dbg_info(&expression->expression.source_position);
+       ir_node  *value = create_arithmetic_binop(expression, func);
+       type_t   *type  = expression->expression.datatype;
+       ir_mode  *mode  = get_ir_mode(type);
+
+       value = create_conv(dbgi, value, mode);
+       set_value_for_expression(expression->left, value);
+
+       return value;
+}
+
 static ir_node *create_add(const binary_expression_t *expression)
 {
        dbg_info *dbgi  = get_dbg_info(&expression->expression.source_position);
@@ -1003,6 +1020,35 @@ static ir_node *create_sub(const binary_expression_t *expression)
        return res;
 }
 
+static ir_node *create_divmod(const binary_expression_t *expression)
+{
+       dbg_info *dbgi  = get_dbg_info(&expression->expression.source_position);
+       ir_node  *left  = expression_to_firm(expression->left);
+       ir_node  *right = expression_to_firm(expression->right);
+       ir_node  *pin   = new_Pin(new_NoMem());
+       type_t   *type  = expression->expression.datatype;
+       ir_mode  *mode  = get_ir_mode(type);
+       ir_node  *op;
+       ir_node  *res;
+
+       if(expression->type == BINEXPR_DIV) {
+               if(mode_is_float(mode)) {
+                       op  = new_d_Quot(dbgi, pin, left, right, mode, op_pin_state_floats);
+                       res = new_d_Proj(dbgi, op, mode, pn_Quot_res);
+               } else {
+                       op  = new_d_Div(dbgi, pin, left, right, mode, op_pin_state_floats);
+                       res = new_d_Proj(dbgi, op, mode, pn_Div_res);
+               }
+       } else {
+               assert(expression->type == BINEXPR_MOD);
+               assert(!mode_is_float(mode));
+               op  = new_d_Mod(dbgi, pin, left, right, mode, op_pin_state_floats);
+               res = new_d_Proj(dbgi, op, mode, pn_Mod_res);
+       }
+
+       return res;
+}
+
 
 
 static ir_node *binary_expression_to_firm(const binary_expression_t *expression)
@@ -1044,9 +1090,31 @@ static ir_node *binary_expression_to_firm(const binary_expression_t *expression)
                return create_arithmetic_binop(expression, new_d_Shl);
        case BINEXPR_SHIFTRIGHT:
                return create_arithmetic_binop(expression, new_d_Shr);
+       case BINEXPR_DIV:
+       case BINEXPR_MOD:
+               return create_divmod(expression);
        case BINEXPR_LOGICAL_AND:
        case BINEXPR_LOGICAL_OR:
                return create_lazy_op(expression);
+       case BINEXPR_COMMA:
+               expression_to_firm(expression->left);
+               return expression_to_firm(expression->right);
+       case BINEXPR_ADD_ASSIGN:
+               return create_arithmetic_assign_binop(expression, new_d_Add);
+       case BINEXPR_SUB_ASSIGN:
+               return create_arithmetic_assign_binop(expression, new_d_Sub);
+       case BINEXPR_MUL_ASSIGN:
+               return create_arithmetic_assign_binop(expression, new_d_Mul);
+       case BINEXPR_BITWISE_AND_ASSIGN:
+               return create_arithmetic_assign_binop(expression, new_d_And);
+       case BINEXPR_BITWISE_OR_ASSIGN:
+               return create_arithmetic_assign_binop(expression, new_d_Or);
+       case BINEXPR_BITWISE_XOR_ASSIGN:
+               return create_arithmetic_assign_binop(expression, new_d_Eor);
+       case BINEXPR_SHIFTLEFT_ASSIGN:
+               return create_arithmetic_assign_binop(expression, new_d_Shl);
+       case BINEXPR_SHIFTRIGHT_ASSIGN:
+               return create_arithmetic_assign_binop(expression, new_d_Shr);
        default:
                panic("TODO binexpr type");
        }
index aafbc36..fb011da 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -2250,55 +2250,17 @@ static expression_t *parse_select_expression(unsigned precedence,
        return (expression_t*) select;
 }
 
-static expression_t *parse_call_expression(unsigned precedence,
-                                           expression_t *expression)
+static expression_t *create_cast_expression(expression_t *expression,
+                                            type_t *dest_type)
 {
-       (void) precedence;
-       call_expression_t *call = allocate_ast_zero(sizeof(call[0]));
-       call->expression.type   = EXPR_CALL;
-       call->function          = expression;
-
-       type_t *type = expression->datatype;
-       if(type->type != TYPE_FUNCTION) {
-               /* TODO calling pointers to functions is ok */
-               parser_print_error_prefix();
-               fputs("called object '", stderr);
-               print_expression(expression);
-               fputs("' (type ", stderr);
-               print_type(type);
-               fputs("is not a function\n", stderr);
-
-               call->expression.datatype = NULL;
-       } else {
-               function_type_t *function_type = (function_type_t*) type;
-               call->expression.datatype = function_type->result_type;
-       }
-
-       /* parse arguments */
-       eat('(');
-
-       if(token.type != ')') {
-               call_argument_t *last_argument = NULL;
-
-               while(true) {
-                       call_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
-
-                       argument->expression = parse_assignment_expression();
-                       if(last_argument == NULL) {
-                               call->arguments = argument;
-                       } else {
-                               last_argument->next = argument;
-                       }
-                       last_argument = argument;
+       unary_expression_t *cast = allocate_ast_zero(sizeof(cast[0]));
 
-                       if(token.type != ',')
-                               break;
-                       next_token();
-               }
-       }
-       expect(')');
+       cast->expression.type     = EXPR_UNARY;
+       cast->type                = UNEXPR_CAST;
+       cast->value               = expression;
+       cast->expression.datatype = dest_type;
 
-       return (expression_t*) call;
+       return (expression_t*) cast;
 }
 
 static void type_error(const char *msg, const source_position_t source_position,
@@ -2323,28 +2285,32 @@ static void type_error_incompatible(const char *msg,
        error();
 }
 
-static type_t *get_type_after_conversion(const type_t *type1,
-                                         const type_t *type2)
+static int get_rank(const type_t *type)
 {
-       /* TODO... */
-       (void) type2;
-       return (type_t*) type1;
+       /* The C-standard allows promoting to int or unsigned int (see § 7.2.2
+        * and esp. footnote 108). However we can't fold constants (yet), so we
+        * can't decide wether unsigned int is possible, while int always works.
+        * (unsigned int would be preferable when possible... for stuff like
+        *  struct { enum { ... } bla : 4; } ) */
+       if(type->type == TYPE_ENUM)
+               return ATOMIC_TYPE_INT;
+
+       assert(type->type == TYPE_ATOMIC);
+       atomic_type_t      *atomic_type = (atomic_type_t*) type;
+       atomic_type_type_t  atype       = atomic_type->atype;
+       return atype;
 }
 
-static expression_t *create_cast_expression(expression_t *expression,
-                                            type_t *dest_type)
+static type_t *promote_integer(type_t *type)
 {
-       unary_expression_t *cast = allocate_ast_zero(sizeof(cast[0]));
-
-       cast->expression.type     = EXPR_UNARY;
-       cast->type                = UNEXPR_CAST;
-       cast->value               = expression;
-       cast->expression.datatype = dest_type;
+       if(get_rank(type) < ATOMIC_TYPE_INT)
+               type = type_int;
 
-       return (expression_t*) cast;
+       return type;
 }
 
-static expression_t *create_cast(expression_t *expression, type_t *dest_type)
+static expression_t *create_implicit_cast(expression_t *expression,
+                                          type_t *dest_type)
 {
        assert(expression->datatype != NULL);
        type_t *source_type = expression->datatype;
@@ -2369,6 +2335,108 @@ static expression_t *create_cast(expression_t *expression, type_t *dest_type)
        panic("casting of non-atomic types not implemented yet");
 }
 
+static expression_t *parse_call_expression(unsigned precedence,
+                                           expression_t *expression)
+{
+       (void) precedence;
+       call_expression_t *call = allocate_ast_zero(sizeof(call[0]));
+       call->expression.type   = EXPR_CALL;
+       call->function          = expression;
+
+       function_type_t *function_type;
+       type_t          *type = expression->datatype;
+       if(type->type != TYPE_FUNCTION) {
+               /* TODO calling pointers to functions is ok */
+               parser_print_error_prefix();
+               fputs("called object '", stderr);
+               print_expression(expression);
+               fputs("' (type ", stderr);
+               print_type(type);
+               fputs("is not a function\n", stderr);
+
+               function_type             = NULL;
+               call->expression.datatype = NULL;
+       } else {
+               function_type             = (function_type_t*) type;
+               call->expression.datatype = function_type->result_type;
+       }
+
+       /* parse arguments */
+       eat('(');
+
+       if(token.type != ')') {
+               call_argument_t *last_argument = NULL;
+
+               while(true) {
+                       call_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
+
+                       argument->expression = parse_assignment_expression();
+                       if(last_argument == NULL) {
+                               call->arguments = argument;
+                       } else {
+                               last_argument->next = argument;
+                       }
+                       last_argument = argument;
+
+                       if(token.type != ',')
+                               break;
+                       next_token();
+               }
+       }
+       expect(')');
+
+       if(function_type != NULL) {
+               function_parameter_t *parameter = function_type->parameters;
+               call_argument_t      *argument  = call->arguments;
+               for( ; parameter != NULL && argument != NULL;
+                               parameter = parameter->next, argument = argument->next) {
+                       type_t *expected_type = parameter->type;
+                       /* TODO report context in error messages */
+                       argument->expression  = create_implicit_cast(argument->expression,
+                                                                    expected_type);
+               }
+               /* too few parameters */
+               if(parameter != NULL) {
+                       parser_print_error_prefix();
+                       fprintf(stderr, "too few arguments to function '");
+                       print_expression(expression);
+                       fprintf(stderr, "'\n");
+               } else if(argument != NULL) {
+                       /* too many parameters */
+                       if(!function_type->variadic
+                                       && !function_type->unspecified_parameters) {
+                               parser_print_error_prefix();
+                               fprintf(stderr, "too many arguments to function '");
+                               print_expression(expression);
+                               fprintf(stderr, "'\n");
+                       } else {
+                               /* do default promotion */
+                               for( ; argument != NULL; argument = argument->next) {
+                                       type_t *type = argument->expression->datatype;
+
+                                       if(is_type_integer(type)) {
+                                               type = promote_integer(type);
+                                       } else if(type == type_float) {
+                                               type = type_double;
+                                       }
+                                       argument->expression
+                                               = create_implicit_cast(argument->expression, type);
+                               }
+                       }
+               }
+       }
+
+       return (expression_t*) call;
+}
+
+static type_t *get_type_after_conversion(const type_t *type1,
+                                         const type_t *type2)
+{
+       /* TODO... */
+       (void) type2;
+       return (type_t*) type1;
+}
+
 static expression_t *parse_conditional_expression(unsigned precedence,
                                                   expression_t *expression)
 {
@@ -2510,75 +2578,40 @@ CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_PLUSPLUS,   UNEXPR_POSTFIX_INCREMENT,
 CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_MINUSMINUS, UNEXPR_POSTFIX_DECREMENT,
                                        get_unexpr_arithmetic_type)
 
-static int get_rank(const type_t *type)
-{
-       /* The C-standard allows promoting to int or unsigned int (see § 7.2.2
-        * and esp. footnote 108). However we can't fold constants (yet), so we
-        * can't decide wether unsigned int is possible, while int always works.
-        * (unsigned int would be preferable when possible... for stuff like
-        *  struct { enum { ... } bla : 4; } ) */
-       if(type->type == TYPE_ENUM)
-               return ATOMIC_TYPE_INT;
-
-       assert(type->type == TYPE_ATOMIC);
-       atomic_type_t      *atomic_type = (atomic_type_t*) type;
-       atomic_type_type_t  atype       = atomic_type->atype;
-       return atype;
-}
-
-static void semantic_arithmetic(expression_t **left, expression_t **right)
+static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
 {
-       type_t *type_left  = (*left)->datatype;
-       type_t *type_right = (*right)->datatype;
-       type_left  = skip_typeref(type_left);
-       type_right = skip_typeref(type_right);
-
        /* TODO: handle complex + imaginary types */
 
        /* § 6.3.1.8 Usual arithmetic conversions */
        if(type_left == type_long_double || type_right == type_long_double) {
-               type_left  = type_long_double;
-               type_right = type_long_double;
-               goto finished;
+               return type_long_double;
        } else if(type_left == type_double || type_right == type_double) {
-               type_left  = type_double;
-               type_right = type_double;
-               goto finished;
+               return type_double;
        } else if(type_left == type_float || type_right == type_float) {
-               type_left  = type_float;
-               type_right = type_float;
-               goto finished;
+               return type_float;
        }
 
-       /* integer promotion */
-       if(get_rank(type_left) < ATOMIC_TYPE_INT)
-               type_left = type_int;
-       if(get_rank(type_right) < ATOMIC_TYPE_INT)
-               type_right = type_int;
+       type_right = promote_integer(type_right);
+       type_left  = promote_integer(type_left);
 
        if(type_left == type_right)
-               goto finished;
+               return type_left;
 
        bool signed_left  = is_type_signed(type_left);
        bool signed_right = is_type_signed(type_right);
        if(get_rank(type_left) < get_rank(type_right)) {
                if(signed_left == signed_right || !signed_right) {
-                       type_left = type_right;
+                       return type_right;
                } else {
-                       type_right = type_left;
+                       return type_left;
                }
        } else {
                if(signed_left == signed_right || !signed_left) {
-                       type_right = type_left;
+                       return type_left;
                } else {
-                       type_left = type_right;
+                       return type_right;
                }
        }
-
-finished:
-       assert(type_left == type_right);
-       *left  = create_cast(*left, type_left);
-       *right = create_cast(*right, type_right);
 }
 
 static void semantic_binexpr_arithmetic(binary_expression_t *expression)
@@ -2595,8 +2628,10 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression)
                return;
        }
 
-       semantic_arithmetic(&expression->left, &expression->right);
-       expression->expression.datatype = expression->left->datatype;
+       type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+       expression->left  = create_implicit_cast(left, arithmetic_type);
+       expression->right = create_implicit_cast(right, arithmetic_type);
+       expression->expression.datatype = arithmetic_type;
 }
 
 static void semantic_add(binary_expression_t *expression)
@@ -2610,8 +2645,10 @@ static void semantic_add(binary_expression_t *expression)
 
        /* § 5.6.5 */
        if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
-               semantic_arithmetic(&expression->left, &expression->right);
-               expression->expression.datatype = expression->left->datatype;
+               type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+               expression->left  = create_implicit_cast(left, arithmetic_type);
+               expression->right = create_implicit_cast(right, arithmetic_type);
+               expression->expression.datatype = arithmetic_type;
                return;
        } else if(type_left->type == TYPE_POINTER && is_type_integer(type_right)) {
                expression->expression.datatype = type_left;
@@ -2638,8 +2675,10 @@ static void semantic_sub(binary_expression_t *expression)
 
        /* § 5.6.5 */
        if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
-               semantic_arithmetic(&expression->left, &expression->right);
-               expression->expression.datatype = expression->left->datatype;
+               type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+               expression->left  = create_implicit_cast(left, arithmetic_type);
+               expression->right = create_implicit_cast(right, arithmetic_type);
+               expression->expression.datatype = arithmetic_type;
                return;
        } else if(type_left->type == TYPE_POINTER && is_type_integer(type_right)) {
                expression->expression.datatype = type_left;
@@ -2672,8 +2711,12 @@ static void semantic_comparison(binary_expression_t *expression)
        type_t       *type_left  = left->datatype;
        type_t       *type_right = right->datatype;
 
+       /* TODO non-arithmetic types */
        if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
-               semantic_arithmetic(&expression->left, &expression->right);
+               type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+               expression->left  = create_implicit_cast(left, arithmetic_type);
+               expression->right = create_implicit_cast(right, arithmetic_type);
+               expression->expression.datatype = arithmetic_type;
        }
        expression->expression.datatype = type_int;
 }
@@ -2692,8 +2735,12 @@ static void semantic_arithmetic_assign(binary_expression_t *expression)
                return;
        }
 
-       semantic_arithmetic(&expression->left, &expression->right);
-       /* note that we assign the original type_left before casting */
+       /* combined instructions are tricky. We can't create an implicit cast on
+        * the left side, because we need the uncasted form for the store.
+        * The ast2firm pass has to know that left_type must be right_type
+        * for the arithmeitc operation and create a cast by itself */
+       type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
+       expression->right       = create_implicit_cast(right, arithmetic_type);
        expression->expression.datatype = type_left;
 }
 
@@ -2713,7 +2760,7 @@ static void semantic_assign(type_t *orig_type_left, expression_t **right,
        if(type_left == type_right) {
                /* fine */
        } else if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
-               *right = create_cast(*right, type_left);
+               *right = create_implicit_cast(*right, type_left);
        } else if(type_left->type == TYPE_POINTER
                        && type_right->type == TYPE_POINTER) {
                /* TODO */
index de76857..b47f7b5 100644 (file)
--- a/type_t.h
+++ b/type_t.h
@@ -103,11 +103,11 @@ struct function_parameter_t {
 };
 
 struct function_type_t {
-       type_t               type;
-       type_t              *result_type;
+       type_t                type;
+       type_t               *result_type;
        function_parameter_t *parameters;
-       bool                 variadic;
-       bool                 unspecified_parameters;
+       bool                  variadic;
+       bool                  unspecified_parameters;
 };
 
 struct compound_type_t {