This implements my idea of how POINTER_PLUS_EXPR should end up being changed. This addresses two things, 1) reduce the use of sizetype nodes, 2) properly handle targets where sizeof (void *) != sizeof (sizetype). Especially 2) is important as currently we lose information about the signedness of the offset and thus have no idea on whether to sign- or zero-extend.
The following patch just implements the different checking and handles the desired semantics during expansion. It does not yet touch the various places that build POINTER_PLUS_EXPRs (in fact, a sizetype offset operand is still valid). A final transition will be as tedious as the original patch introducing POINTER_PLUS_EXPRs, but the obvious starting points are the frontends and fold. Partial transitions will of course also eventually expose issues with this new design. Like, how do we fold (p + short a) + unsigned int b. Straight-forward answer: as p + ((uintptr_t)a + (uintptr_t)b). Which we eventually can narrow again if we know sth about the value-ranges of a and b (remember, overflow in ptr + offset is undefined). Comments? Thanks, Richard. 2011-06-17 Richard Guenther <rguent...@suse.de> * expr.c (expand_expr_real_2): Extend the POINTER_PLUS_EXPR offset operand to pointer precision. * tree-cfg.c (verify_expr): Allow arbitrary integral types for the POINTER_PLUS_EXPR offset operand. (verify_gimple_assign_binary): Likewise. * tree.c (build2_stat): Likewise. * tree.def (POINTER_PLUS_EXPR): Adjust documentation. Index: trunk/gcc/expr.c =================================================================== *** trunk.orig/gcc/expr.c 2011-06-16 16:56:02.000000000 +0200 --- trunk/gcc/expr.c 2011-06-17 11:33:52.000000000 +0200 *************** expand_expr_real_2 (sepops ops, rtx targ *** 7422,7436 **** } case POINTER_PLUS_EXPR: ! /* Even though the sizetype mode and the pointer's mode can be different ! expand is able to handle this correctly and get the correct result out ! of the PLUS_EXPR code. */ ! /* Make sure to sign-extend the sizetype offset in a POINTER_PLUS_EXPR ! if sizetype precision is smaller than pointer precision. */ ! if (TYPE_PRECISION (sizetype) < TYPE_PRECISION (type)) ! treeop1 = fold_convert_loc (loc, type, ! fold_convert_loc (loc, ssizetype, ! treeop1)); case PLUS_EXPR: /* If we are adding a constant, a VAR_DECL that is sp, fp, or ap, and something else, make sure we add the register to the constant and --- 7422,7433 ---- } case POINTER_PLUS_EXPR: ! /* Extend/truncate the offset operand to pointer width according ! to its signedness. */ ! if (TYPE_PRECISION (type) != TYPE_PRECISION (treeop1)) ! treeop1 = fold_convert_loc (loc, type, treeop1); ! ! /* Fallthru. */ case PLUS_EXPR: /* If we are adding a constant, a VAR_DECL that is sp, fp, or ap, and something else, make sure we add the register to the constant and Index: trunk/gcc/tree-cfg.c =================================================================== *** trunk.orig/gcc/tree-cfg.c 2011-06-16 16:55:45.000000000 +0200 --- trunk/gcc/tree-cfg.c 2011-06-17 11:35:17.000000000 +0200 *************** verify_expr (tree *tp, int *walk_subtree *** 2845,2857 **** error ("invalid operand to pointer plus, first operand is not a pointer"); return t; } ! /* Check to make sure the second operand is an integer with type of ! sizetype. */ ! if (!useless_type_conversion_p (sizetype, ! TREE_TYPE (TREE_OPERAND (t, 1)))) { error ("invalid operand to pointer plus, second operand is not an " ! "integer with type of sizetype"); return t; } /* FALLTHROUGH */ --- 2845,2855 ---- error ("invalid operand to pointer plus, first operand is not a pointer"); return t; } ! /* Check to make sure the second operand is an integer. */ ! if (!INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (t, 1)))) { error ("invalid operand to pointer plus, second operand is not an " ! "integer type"); return t; } /* FALLTHROUGH */ *************** verify_gimple_assign_binary (gimple stmt *** 3609,3615 **** do_pointer_plus_expr_check: if (!POINTER_TYPE_P (rhs1_type) || !useless_type_conversion_p (lhs_type, rhs1_type) ! || !useless_type_conversion_p (sizetype, rhs2_type)) { error ("type mismatch in pointer plus expression"); debug_generic_stmt (lhs_type); --- 3607,3613 ---- do_pointer_plus_expr_check: if (!POINTER_TYPE_P (rhs1_type) || !useless_type_conversion_p (lhs_type, rhs1_type) ! || !INTEGRAL_TYPE_P (rhs2_type)) { error ("type mismatch in pointer plus expression"); debug_generic_stmt (lhs_type); Index: trunk/gcc/tree.c =================================================================== *** trunk.orig/gcc/tree.c 2011-06-16 16:55:45.000000000 +0200 --- trunk/gcc/tree.c 2011-06-17 11:29:35.000000000 +0200 *************** build2_stat (enum tree_code code, tree t *** 3779,3786 **** if (code == POINTER_PLUS_EXPR && arg0 && arg1 && tt) gcc_assert (POINTER_TYPE_P (tt) && POINTER_TYPE_P (TREE_TYPE (arg0)) ! && INTEGRAL_TYPE_P (TREE_TYPE (arg1)) ! && useless_type_conversion_p (sizetype, TREE_TYPE (arg1))); t = make_node_stat (code PASS_MEM_STAT); TREE_TYPE (t) = tt; --- 3779,3785 ---- if (code == POINTER_PLUS_EXPR && arg0 && arg1 && tt) gcc_assert (POINTER_TYPE_P (tt) && POINTER_TYPE_P (TREE_TYPE (arg0)) ! && INTEGRAL_TYPE_P (TREE_TYPE (arg1))); t = make_node_stat (code PASS_MEM_STAT); TREE_TYPE (t) = tt; Index: trunk/gcc/tree.def =================================================================== *** trunk.orig/gcc/tree.def 2011-06-16 14:49:31.000000000 +0200 --- trunk/gcc/tree.def 2011-06-17 11:41:04.000000000 +0200 *************** DEFTREECODE (MINUS_EXPR, "minus_expr", t *** 610,616 **** DEFTREECODE (MULT_EXPR, "mult_expr", tcc_binary, 2) /* Pointer addition. The first operand is always a pointer and the ! second operand is an integer of type sizetype. */ DEFTREECODE (POINTER_PLUS_EXPR, "pointer_plus_expr", tcc_binary, 2) /* Division for integer result that rounds the quotient toward zero. */ --- 610,617 ---- DEFTREECODE (MULT_EXPR, "mult_expr", tcc_binary, 2) /* Pointer addition. The first operand is always a pointer and the ! second operand is an integer. The second operand is implicitly ! extended to the width of the first operand. */ DEFTREECODE (POINTER_PLUS_EXPR, "pointer_plus_expr", tcc_binary, 2) /* Division for integer result that rounds the quotient toward zero. */