This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch,loopiv] misaligned packed array memory access


The attached test case reduces a misaligned field access from an array of packed structs. In this example compiled with -O2 the field wMaxPacketSize is accessed (on sh4) with a mov.w instruction although it is byte aligned.

The tree-ssa-loop ivopts did not check packed struct offsets indexed by an induction variable. Thus if the struct size is not aligned, the field becomes unaligned after the first iteration even if it was aligned from the base of this structure.

This patch solves this problem by expanding may_be_unaligned_p to check that a loop carried offset is a multiple of the desired alignment.

This bug impacted STRICT_ALIGNMENT targets. I regtested on sh-superh-elf and sh4-linux-gnu.

Also bootstraped for i686-pc-linux-gnu.

Thanks you for any feedback and trunk approval if ok.

-c

2008-01-28 Christian Bruel <christian.bruel@st.com>

	* tree-ssa-loop-ivopts.c (may_be_unaligned_p): check loop carried offset.
	* (loop_offset_multiple_of): new function.



Index: tree-ssa-loop-ivopts.c
===================================================================
--- tree-ssa-loop-ivopts.c	(revision 131825)
+++ tree-ssa-loop-ivopts.c	(working copy)
@@ -1378,10 +1378,13 @@
   return true;
 }
 
+static bool
+loop_offset_multiple_of (struct ivopts_data *, tree , tree);
+
 /* Returns true if memory reference REF may be unaligned.  */
 
 static bool
-may_be_unaligned_p (tree ref)
+may_be_unaligned_p (struct ivopts_data *data, tree ref)
 {
   tree base;
   tree base_type;
@@ -1405,11 +1408,18 @@
   base_type = TREE_TYPE (base);
   base_align = TYPE_ALIGN (base_type);
 
-  if (mode != BLKmode
-      && (base_align < GET_MODE_ALIGNMENT (mode)
+  if (mode != BLKmode) {
+      if (base_align < GET_MODE_ALIGNMENT (mode)
 	  || bitpos % GET_MODE_ALIGNMENT (mode) != 0
-	  || bitpos % BITS_PER_UNIT != 0))
-    return true;
+	  || bitpos % BITS_PER_UNIT != 0) 
+	return true;
+      
+      if (toffset && contains_packed_reference (ref)) {
+	tree al = build_int_cst (NULL_TREE, GET_MODE_ALIGNMENT (mode) / BITS_PER_UNIT);
+	if (!loop_offset_multiple_of (data, toffset, al))
+	  return true;
+      } 
+  }
 
   return false;
 }
@@ -1467,7 +1477,7 @@
     goto fail;
 
   if (STRICT_ALIGNMENT
-      && may_be_unaligned_p (base))
+      && may_be_unaligned_p (data, base))
     goto fail;
 
   base = unshare_expr (base);
@@ -2566,6 +2576,63 @@
     }
 }
 
+/* Returns true if OFFSET is always a multiple of alignment AL
+   even if loop carried.  */
+
+static bool
+loop_offset_multiple_of (struct ivopts_data *data, tree offset, tree al)
+{
+  double_int mul;
+
+  STRIP_NOPS (offset);
+
+  if (TREE_CODE (offset) == SSA_NAME) {
+    struct iv *civ = get_iv (data, offset);
+    if (!civ || constant_multiple_of (offset, al, &mul))
+      return true;
+  }
+
+  if (TREE_CODE (offset) == MULT_EXPR) {
+    tree op0 = TREE_OPERAND (offset, 0);
+    tree op1 = TREE_OPERAND (offset, 1);
+    STRIP_NOPS (op0);
+    STRIP_NOPS (op1);
+
+    if (TREE_CODE (op1) != INTEGER_CST)
+      return false;
+      
+    if (TREE_CODE (op0) == SSA_NAME) {
+      struct iv *civ = get_iv (data, op0);
+      tree type = TREE_TYPE (op1);
+      if (!civ)
+	return true;
+
+      tree val = fold_build2 (PLUS_EXPR, type, civ->base, 
+			      fold_build2 (MULT_EXPR, type, civ->step, op1));
+
+      if (constant_multiple_of (val, al, &mul))
+	return true;
+    }
+    else if (loop_offset_multiple_of (data, op0, al))
+      return true;
+  }
+
+  else if (TREE_CODE (offset) == PLUS_EXPR
+	   || TREE_CODE (offset) == MINUS_EXPR) {
+    tree op0 = TREE_OPERAND (offset, 0);
+    tree op1 = TREE_OPERAND (offset, 1);
+    if (loop_offset_multiple_of (data, op0, al) &&
+	loop_offset_multiple_of (data, op1, al))
+      return true;
+  }
+
+  else if (TREE_CODE (offset) == INTEGER_CST) {
+    return constant_multiple_of (offset, al, &mul);
+  }
+
+  return false;
+}
+
 /* If A is (TYPE) BA and B is (TYPE) BB, and the types of BA and BB have the
    same precision that is at least as wide as the precision of TYPE, stores
    BA to A and BB to B, and returns the type of BA.  Otherwise, returns the
struct usb_interface_descriptor {
 unsigned short wMaxPacketSize;
  char e;
} __attribute__ ((packed));

struct usb_device {
 int devnum;
 struct usb_interface_descriptor if_desc[2];
};

extern void foo (unsigned short);

void usb_set_maxpacket(struct usb_device *dev, int n)
{
  int i;

  for(i=0; i<n;i++)
    foo(dev->if_desc[i].wMaxPacketSize);
}




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]