Implement pointer arithmetic for += and -=. (Hopefully) fix pointer arithmetic for -.
authorChristoph Mallon <christoph.mallon@gmx.de>
Sat, 17 Nov 2007 19:14:03 +0000 (19:14 +0000)
committerChristoph Mallon <christoph.mallon@gmx.de>
Sat, 17 Nov 2007 19:14:03 +0000 (19:14 +0000)
[r18456]

ast2firm.c
parser.c

index 6947b74..2ec9b96 100644 (file)
@@ -973,16 +973,44 @@ static ir_node *create_arithmetic_binop(const binary_expression_t *expression,
        return res;
 }
 
+static ir_node *pointer_arithmetic(ir_node  *const pointer,
+                                   ir_node  *      integer,
+                                   type_t   *const type,
+                                   dbg_info *const dbgi,
+                                   const create_arithmetic_func func)
+{
+       pointer_type_t *const pointer_type = (pointer_type_t*)type;
+       type_t         *const points_to    = pointer_type->points_to;
+       const unsigned        elem_size    = get_type_size(points_to);
+
+       assert(elem_size >= 1);
+       if (elem_size > 1) {
+               integer             = create_conv(dbgi, integer, mode_Is);
+               ir_node *const cnst = new_Const_long(mode_Is, (long)elem_size);
+               ir_node *const mul  = new_d_Mul(dbgi, integer, cnst, mode_Is);
+               integer = mul;
+       }
+
+       ir_mode *const mode = get_ir_mode(type);
+       return func(dbgi, pointer, integer, mode);
+}
+
 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);
+       dbg_info *const dbgi = get_dbg_info(&expression->expression.source_position);
+       type_t   *const type = expression->expression.datatype;
+       ir_node  *value;
 
-       assert(type->type != TYPE_POINTER);
+       if (type->type == TYPE_POINTER) {
+               ir_node        *const pointer = expression_to_firm(expression->left);
+               ir_node        *      integer = expression_to_firm(expression->right);
+               value = pointer_arithmetic(pointer, integer, type, dbgi, func);
+       } else {
+               value = create_arithmetic_binop(expression, func);
+       }
 
+       ir_mode  *const mode = get_ir_mode(type);
        value = create_conv(dbgi, value, mode);
        set_value_for_expression(expression->left, value);
 
@@ -995,7 +1023,6 @@ static ir_node *create_add(const binary_expression_t *expression)
        ir_node  *left  = expression_to_firm(expression->left);
        ir_node  *right = expression_to_firm(expression->right);
        type_t   *type  = expression->expression.datatype;
-       ir_mode  *mode  = get_ir_mode(type);
 
        expression_t *expr_left  = expression->left;
        expression_t *expr_right = expression->right;
@@ -1003,76 +1030,37 @@ static ir_node *create_add(const binary_expression_t *expression)
        type_t       *type_right = skip_typeref(expr_right->datatype);
 
        if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
+               ir_mode *const mode = get_ir_mode(type);
                return new_d_Add(dbgi, left, right, mode);
        }
 
-       ir_node        *pointer;
-       ir_node        *integer;
-       pointer_type_t *pointer_type;
        if(type_left->type == TYPE_POINTER) {
-               pointer      = left;
-               integer      = right;
-               pointer_type = (pointer_type_t*) type_left;
+               return pointer_arithmetic(left, right, type_left, dbgi, new_d_Add);
        } else {
                assert(type_right->type == TYPE_POINTER);
-               pointer      = right;
-               integer      = left;
-               pointer_type = (pointer_type_t*) type_right;
+               return pointer_arithmetic(right, left, type_right, dbgi, new_d_Add);
        }
-
-       type_t   *points_to = pointer_type->points_to;
-       unsigned  elem_size = get_type_size(points_to);
-
-       assert(elem_size >= 1);
-       if(elem_size > 1) {
-               integer       = create_conv(dbgi, integer, mode_Is);
-               ir_node *cnst = new_Const_long(mode_Is, (int) elem_size);
-               ir_node *mul  = new_d_Mul(dbgi, integer, cnst, mode_Is);
-               integer = mul;
-       }
-
-       ir_node *res = new_d_Add(dbgi, pointer, integer, mode);
-
-       return res;
 }
 
 static ir_node *create_sub(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;
-       ir_mode  *mode  = get_ir_mode(type);
-
-       expression_t *expr_left  = expression->left;
-       expression_t *expr_right = expression->right;
-       type_t       *type_left  = skip_typeref(expr_left->datatype);
-       type_t       *type_right = skip_typeref(expr_right->datatype);
-
-       if((is_type_arithmetic(type_left) && is_type_arithmetic(type_right))
-                       || (type_left->type == TYPE_POINTER
-                               && type_right->type == TYPE_POINTER)) {
+       dbg_info *const dbgi  = get_dbg_info(&expression->expression.source_position);
+       expression_t *const expr_left  = expression->left;
+       expression_t *const expr_right = expression->right;
+       ir_node      *const left       = expression_to_firm(expr_left);
+       ir_node      *const right      = expression_to_firm(expr_right);
+       type_t       *const type       = expression->expression.datatype;
+       type_t       *const type_left  = skip_typeref(expr_left->datatype);
+       type_t       *const type_right = skip_typeref(expr_right->datatype);
+
+       if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
+           (type_left->type == TYPE_POINTER && type_right->type == TYPE_POINTER)) {
+               ir_mode *const mode = get_ir_mode(type);
                return new_d_Sub(dbgi, left, right, mode);
        }
 
-       assert(type_right->type == TYPE_POINTER);
-       ir_node        *pointer      = left;
-       ir_node        *integer      = right;
-       pointer_type_t *pointer_type = (pointer_type_t*) type_right;
-
-       type_t   *points_to = pointer_type->points_to;
-       unsigned  elem_size = get_type_size(points_to);
-
-       assert(elem_size >= 1);
-       if(elem_size > 1) {
-               ir_node *cnst = new_Const_long(mode_Iu, elem_size);
-               ir_node *mul  = new_d_Mul(dbgi, integer, cnst, mode_Iu);
-               integer = mul;
-       }
-
-       ir_node *res = new_d_Sub(dbgi, pointer, integer, mode);
-
-       return res;
+       assert(type_left->type == TYPE_POINTER);
+       return pointer_arithmetic(left, right, type_left, dbgi, new_d_Sub);
 }
 
 static ir_node *create_shift(const binary_expression_t *expression)
index 4c4208c..dbc6630 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -3173,6 +3173,40 @@ static void semantic_arithmetic_assign(binary_expression_t *expression)
        expression->expression.datatype = type_left;
 }
 
+static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
+{
+       expression_t *left            = expression->left;
+       expression_t *right           = expression->right;
+       type_t       *orig_type_left  = left->datatype;
+       type_t       *orig_type_right = right->datatype;
+
+       if(orig_type_left == NULL || orig_type_right == NULL)
+               return;
+
+       type_t *type_left  = skip_typeref(orig_type_left);
+       type_t *type_right = skip_typeref(orig_type_right);
+
+       if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
+               /* 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 *const arithmetic_type = semantic_arithmetic(type_left, type_right);
+               expression->right = create_implicit_cast(right, arithmetic_type);
+               expression->expression.datatype = type_left;
+       } else if (type_left->type == TYPE_POINTER && is_type_integer(type_right)) {
+               expression->expression.datatype = type_left;
+       } else {
+               parser_print_error_prefix();
+               fputs("Incompatible types ", stderr);
+               print_type_quoted(orig_type_left);
+               fputs(" and ", stderr);
+               print_type_quoted(orig_type_right);
+               fputs(" in assignment\n", stderr);
+               return;
+       }
+}
+
 static void semantic_logical_op(binary_expression_t *expression)
 {
        expression_t *left            = expression->left;
@@ -3260,9 +3294,9 @@ CREATE_BINEXPR_PARSER(T_LESSLESS, BINEXPR_SHIFTLEFT,
 CREATE_BINEXPR_PARSER(T_GREATERGREATER, BINEXPR_SHIFTRIGHT,
                       semantic_shift_op, 1)
 CREATE_BINEXPR_PARSER(T_PLUSEQUAL, BINEXPR_ADD_ASSIGN,
-                      semantic_arithmetic_assign, 0)
+                      semantic_arithmetic_addsubb_assign, 0)
 CREATE_BINEXPR_PARSER(T_MINUSEQUAL, BINEXPR_SUB_ASSIGN,
-                      semantic_arithmetic_assign, 0)
+                      semantic_arithmetic_addsubb_assign, 0)
 CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, BINEXPR_MUL_ASSIGN,
                       semantic_arithmetic_assign, 0)
 CREATE_BINEXPR_PARSER(T_SLASHEQUAL, BINEXPR_DIV_ASSIGN,