[PATCH][mem-ref2] Fix MEM_REF offset extraction

Richard Guenther rguenther@suse.de
Wed Mar 31 10:24:00 GMT 2010


This fixes offset extraction to properly sign-extend.  With
HWI64 and 32bit pointers we otherwise get it wrong.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to
the branch.

Richard.

2010-03-31  Richard Guenther  <rguenther@suse.de>

	* tree.h (mem_ref_offset): Declare.
	* tree.c (mem_ref_offset): New function.
	* tree-ssa-alias.c (refs_may_alias_p_1): Use it.
	* expr.c (get_inner_reference): Likewise.
	(expand_expr_addr_expr_1): Likewise.
	* tree-dfa.c (get_ref_base_and_extent): Likewise.

Index: gcc/tree.c
===================================================================
--- gcc/tree.c	(revision 157699)
+++ gcc/tree.c	(working copy)
@@ -3860,6 +3860,16 @@ build_simple_mem_ref_loc (location_t loc
   return tem;
 }
 
+/* Return the constant offset of a MEM_REF tree T.  */
+
+double_int
+mem_ref_offset (const_tree t)
+{
+  tree toff = TREE_OPERAND (t, 1);
+  return double_int_sext (tree_to_double_int (toff),
+			  TYPE_PRECISION (TREE_TYPE (toff)));
+}
+
 /* Similar except don't specify the TREE_TYPE
    and leave the TREE_SIDE_EFFECTS as 0.
    It is permissible for arguments to be null,
Index: gcc/tree.h
===================================================================
--- gcc/tree.h	(revision 157630)
+++ gcc/tree.h	(working copy)
@@ -4889,6 +4889,7 @@ extern tree fold_indirect_ref_loc (locat
 extern tree build_simple_mem_ref_loc (location_t, tree);
 #define build_simple_mem_ref(T)\
 	build_simple_mem_ref_loc (UNKNOWN_LOCATION, T)
+extern double_int mem_ref_offset (const_tree);
 extern tree constant_boolean_node (int, tree);
 extern tree div_if_zero_remainder (enum tree_code, const_tree, const_tree);
 
Index: gcc/tree-ssa-alias.c
===================================================================
--- gcc/tree-ssa-alias.c	(revision 157827)
+++ gcc/tree-ssa-alias.c	(working copy)
@@ -870,9 +870,9 @@ refs_may_alias_p_1 (ao_ref *ref1, ao_ref
   ind1_p = INDIRECT_REF_P (base1) || (TREE_CODE (base1) == MEM_REF);
   ind2_p = INDIRECT_REF_P (base2) || (TREE_CODE (base2) == MEM_REF);
   if (TREE_CODE (base1) == MEM_REF)
-    offset1 += TREE_INT_CST_LOW (TREE_OPERAND (base1, 1)) * BITS_PER_UNIT;
+    offset1 += mem_ref_offset (base1).low * BITS_PER_UNIT;
   if (TREE_CODE (base2) == MEM_REF)
-    offset2 += TREE_INT_CST_LOW (TREE_OPERAND (base2, 1)) * BITS_PER_UNIT;
+    offset2 += mem_ref_offset (base2).low * BITS_PER_UNIT;
 
   /* Canonicalize the pointer-vs-decl case.  */
   if (ind1_p && var2_p)
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(revision 157630)
+++ gcc/expr.c	(working copy)
@@ -6097,10 +6097,10 @@ get_inner_reference (tree exp, HOST_WIDE
 	      tree off = TREE_OPERAND (exp, 1);
 	      if (!integer_zerop (off))
 		{
+		  double_int coff = mem_ref_offset (exp);
 		  unsigned HOST_WIDE_INT boffl;
 		  HOST_WIDE_INT boffh;
-		  lshift_double (TREE_INT_CST_LOW (off),
-				 TREE_INT_CST_HIGH (off),
+		  lshift_double (coff.low, coff.high,
 				 exact_log2 (BITS_PER_UNIT),
 				 2 * HOST_BITS_PER_WIDE_INT,
 				 &boffl, &boffh, 1);
@@ -6876,7 +6876,8 @@ expand_expr_addr_expr_1 (tree exp, rtx t
 	tree tem = TREE_OPERAND (exp, 0);
 	if (!integer_zerop (TREE_OPERAND (exp, 1)))
 	  tem = build2 (POINTER_PLUS_EXPR, TREE_TYPE (TREE_OPERAND (exp, 1)),
-			tem, fold_convert (sizetype, TREE_OPERAND (exp, 1)));
+			tem,
+			double_int_to_tree (sizetype, mem_ref_offset (exp)));
 	return expand_expr (tem, target, tmode, modifier);
       }
 
Index: gcc/tree-dfa.c
===================================================================
--- gcc/tree-dfa.c	(revision 157630)
+++ gcc/tree-dfa.c	(working copy)
@@ -884,12 +884,13 @@ get_ref_base_and_extent (tree exp, HOST_
 	      /* We do need to handle large offsets here, for example
 	         from gcc.c-torture/compile/pr28489.c.  Thus the whole
 		 function should probably be audited for overflowing
-		 bit_offset ... */
+		 bit_offset ...
+		 Also we need to treat the pointer constants as
+		 sign-extending.  */
 	      && (TREE_INT_CST_HIGH (TREE_OPERAND (exp, 1)) == -1
 		  || host_integerp (TREE_OPERAND (exp, 1), 0)))
 	    {
-	      bit_offset
-		+= TREE_INT_CST_LOW (TREE_OPERAND (exp, 1)) * BITS_PER_UNIT;
+	      bit_offset += mem_ref_offset (exp).low * BITS_PER_UNIT;
 	      exp = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
 	    }
 	  goto done;



More information about the Gcc-patches mailing list