http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58513
Bug ID: 58513
Summary: *var and MEM[(const int &)var] (var has int* type)
are not treated as the same data ref.
Product: gcc
Version: 4.9.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: tree-optimization
Assignee: unassigned at gcc dot gnu.org
Reporter: congh at google dot com
First look at the code below:
int op (const int& x, const int& y) { return x + y; }
void foo(int* a)
{
for (int i = 0; i < 100000; ++i)
a[i] = op(a[i], 1);
}
GCC will generate the following GIMPLE for this loop after inlining op():
<bb 3>:
# i_17 = PHI <0(2), i_23(4)>
# ivtmp_13 = PHI <100000(2), ivtmp_24(4)>
_12 = (long unsigned int) i_17;
_2 = _12 * 4;
_1 = a_6(D) + _2;
_20 = MEM[(const int &)_1];
_19 = _20 + 1;
*_1 = _19;
i_23 = i_17 + 1;
ivtmp_24 = ivtmp_13 - 1;
if (ivtmp_24 != 0)
goto <bb 4>;
else
goto <bb 5>;
Here each element of the array a is loaded by MEM[(const int &)_1] and stored
by *_1, which are the only two data refs in the loop body. The GCC vectorizer
needs to check the possible aliasing between data refs with potential data
dependence. Here those two data refs are actually the same one, but GCC could
not recognize this fact. As a result, the aliasing checking predicate will
always return false at runtime (GCC 4.9 could eliminate this generated branch
at the end of the vectorization pass).
The reason why GCC thinks that MEM[(const int &)_1] and *_1 are two different
data refs is that there is a possible defect in the function operand_equal_p(),
which is used to compare two data refs. The current implementation uses == to
compare the types of the second argument of MEM_REF operator, which is too
strict. Using types_compatible_p() instead can fix the issue above. I have
produced a patch to fix it and the patch is shown below. Please give me the
comment on this patch. (bootstrapping and "make check" passed).
thanks,
Cong
Index: gcc/fold-const.c
===================================================================
--- gcc/fold-const.c (revision 202662)
+++ gcc/fold-const.c (working copy)
@@ -2693,8 +2693,9 @@ operand_equal_p (const_tree arg0, const_
&& operand_equal_p (TYPE_SIZE (TREE_TYPE (arg0)),
TYPE_SIZE (TREE_TYPE (arg1)), flags)))
&& types_compatible_p (TREE_TYPE (arg0), TREE_TYPE (arg1))
- && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg0, 1)))
- == TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg1, 1))))
+ && types_compatible_p (
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg0, 1))),
+ TYPE_MAIN_VARIANT (TREE_TYPE (TREE_OPERAND (arg1, 1))))
&& OP_SAME (0) && OP_SAME (1));
case ARRAY_REF: