This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[patch,loopiv] misaligned packed array memory access
- From: Christian BRUEL <christian dot bruel at st dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 28 Jan 2008 19:36:16 +0100
- Subject: [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);
}