This is a followup fix for the patches from PR41857, which contained a bug that is exposed by the ptx backend. The problem is finding the right pointer type for a mem_ref during ivopts.

The original problem was that on spu-elf, __ea pointers are 64 bit while sizetype is 32 bit. During ivopts, pointer types are typically replaced by unsigned integers in computations, and in the original testcase we have an aff_tree containing only one long long element, but no pointer base, and addr_to_parts casts everything to sizetype, losing parts of the address.

To fix that, code was introduced to promote one of the elements of the aff_tree to become the base, cast it to a pointer of an appropriate type, and thus avoid the conversion to sizetype for that element. This element is the base_hint, which is chosen based on the candidate's base_object.

The problem lies in the following code in move_hint_to_base:

  /* Cast value to appropriate pointer type.  We cannot use a pointer
     to TYPE directly, as the back-end will assume registers of pointer
     type are aligned, and just the base itself may not actually be.
     We use void pointer to the type's address space instead.  */
  qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
  type = build_qualified_type (void_type_node, qual);
  parts->base = fold_convert (build_pointer_type (type), val);

This is confused about address spaces. We can get here with either an integer (for the the original testcase in 4.5, it's a long long that holds the pointer value), but I think we can also arrive here with a pointer. Assuming a normal machine, if it's a long long created by ivopts, TYPE_ADDR_SPACE should be just generic, and if it's some other pointer, we should be looking at TYPE_ADDR_SPACE (TREE_TYPE (type)). Thus, the code seems essentially unnecessary, but - up to this point - harmless.

On ptx however, local variables have an address space, and the above code picks that up and incorrectly places it on the pointer destination type.

The following patch reworks this area - instead of trying to find a proper pointer type, it just recognizes the case where an integer is promoted to be the base, and performs all calculations in that type rather than sizetype. That also seems to be an additional bugfix over the original change, which could still lose address bits in the index. I've verified that this produces the same assembly for the original testcase on spu-elf with the gcc-4_5-branch, and it solves the problems I was seeing on ptx.

Bootstrapped and tested on x86_64-linux. Ok?


Bernd
	* tree-ssa-address.c (move_hint_to_base): Remove arg TYPE.  All
	callers changed.  Don't cast the new base to a pointer type.
	(addr_to_parts): If the base has an integer type, use that instead
	of sizetype for calculations.

Index: gcc/tree-ssa-address.c
===================================================================
--- gcc/tree-ssa-address.c	(revision 436508)
+++ gcc/tree-ssa-address.c	(working copy)
@@ -443,12 +443,10 @@ move_fixed_address_to_symbol (struct mem
 /* If ADDR contains an instance of BASE_HINT, move it to PARTS->base.  */
 
 static void
-move_hint_to_base (tree type, struct mem_address *parts, tree base_hint,
-		   aff_tree *addr)
+move_hint_to_base (struct mem_address *parts, tree base_hint, aff_tree *addr)
 {
   unsigned i;
   tree val = NULL_TREE;
-  int qual;
 
   for (i = 0; i < addr->n; i++)
     {
@@ -463,13 +461,7 @@ move_hint_to_base (tree type, struct mem
   if (i == addr->n)
     return;
 
-  /* Cast value to appropriate pointer type.  We cannot use a pointer
-     to TYPE directly, as the back-end will assume registers of pointer
-     type are aligned, and just the base itself may not actually be.
-     We use void pointer to the type's address space instead.  */
-  qual = ENCODE_QUAL_ADDR_SPACE (TYPE_ADDR_SPACE (type));
-  type = build_qualified_type (void_type_node, qual);
-  parts->base = fold_convert (build_pointer_type (type), val);
+  parts->base = val;
   aff_combination_remove_elt (addr, i);
 }
 
@@ -639,7 +631,7 @@ addr_to_parts (tree type, aff_tree *addr
 	       tree base_hint, struct mem_address *parts,
                bool speed)
 {
-  tree part;
+  tree part, int_type;
   unsigned i;
 
   parts->symbol = NULL_TREE;
@@ -671,21 +663,29 @@ addr_to_parts (tree type, aff_tree *addr
      there is no reliable way how to distinguish between pointer and its
      offset, this is just a guess.  */
   if (!parts->symbol && base_hint)
-    move_hint_to_base (type, parts, base_hint, addr);
+    move_hint_to_base (parts, base_hint, addr);
   if (!parts->symbol && !parts->base)
     move_pointer_to_base (parts, addr);
 
+  /* The call to move_hint_to_base may have promoted an integer to the base.
+     Since addresses in different address spaces can have different sizes, do
+     not cast to sizetype in that case, but use the type of the base.  */
+  if (parts->base && TREE_CODE (TREE_TYPE (parts->base)) == INTEGER_TYPE)
+    int_type = TREE_TYPE (parts->base);
+  else
+    int_type = sizetype;
+
   /* Then try to process the remaining elements.  */
   for (i = 0; i < addr->n; i++)
     {
-      part = fold_convert (sizetype, addr->elts[i].val);
+      part = fold_convert (int_type, addr->elts[i].val);
       if (addr->elts[i].coef != 1)
-	part = fold_build2 (MULT_EXPR, sizetype, part,
-			    wide_int_to_tree (sizetype, addr->elts[i].coef));
+	part = fold_build2 (MULT_EXPR, int_type, part,
+			    wide_int_to_tree (int_type, addr->elts[i].coef));
       add_to_parts (parts, part);
     }
   if (addr->rest)
-    add_to_parts (parts, fold_convert (sizetype, addr->rest));
+    add_to_parts (parts, fold_convert (int_type, addr->rest));
 }
 
 /* Force the PARTS to register.  */

Reply via email to