[backport proposed but not yet approved or applied fix for gcc-4.9/trunk ] List-Archive: Date: Mon, 29 Apr 2013 23:20:59 +0200 From: Bernd Schmidt Subject: MEM_REF representation problem, and folding fix Currently, MEM_REF contains two pointer arguments, one which is supposed to be a base object and another which is supposed to be a constant offset. This representation is somewhat problematic, as not all machines treat pointer values as essentially integers. On machines where size_t is smaller than a pointer, for example m32c where it's due to limitations in the compiler, or the port I've been working on recently where pointers contain a segment selector that does not participate in additions, this is not an accurate representation, and it does cause real issues. It would be better to use a representation more like POINTER_PLUS with a pointer and a real sizetype integer. Can someone explain the comment in tree.def which states that the type of the constant offset is used for TBAA purposes? It states "MEM_REF is equivalent to ((typeof(c))p)->x [...]", so why not represent it as MEM_REF <(desired type)p, (size_t)c>? The following patch works around one instance of the problem. When we fold an offset addition, the addition must be performed in sizetype, otherwise we may get unwanted overflow. This bug triggers on m32c for example, where an offset of 65528 (representing -8) and and offset of 8 are added, yielding an offset of 65536 instead of zero. Solved by performing the intermediate computation in sizetype. Bootstrapped and tested on x86_64-linux (all languages except Ada) with no changes in the tests, and tested on m32c-elf where it fixes 22 failures. Ok? Bernd gcc/ * fold-const.c (fold_binary_loc): When folding an addition in the offset of a memref, use size_type to perform the arithmetic. --- gcc-4.8.0/gcc/fold-const.c.~1~ 2013-02-26 11:00:31.000000000 +0100 +++ gcc-4.8.0/gcc/fold-const.c 2013-04-30 12:13:46.524902703 +0200 @@ -9987,15 +9987,17 @@ fold_binary_loc (location_t loc, && handled_component_p (TREE_OPERAND (arg0, 0))) { tree base; + tree type1 = TREE_TYPE (arg1); HOST_WIDE_INT coffset; base = get_addr_base_and_unit_offset (TREE_OPERAND (arg0, 0), &coffset); if (!base) return NULL_TREE; - return fold_build2 (MEM_REF, type, - build_fold_addr_expr (base), - int_const_binop (PLUS_EXPR, arg1, - size_int (coffset))); + arg1 = fold_convert (size_type_node, arg1); + arg1 = int_const_binop (PLUS_EXPR, arg1, size_int (coffset)); + base = build_fold_addr_expr (base); + arg1 = fold_convert (type1, arg1); + return fold_build2 (MEM_REF, type, base, arg1); } return NULL_TREE;