1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
|
diff -Nur gcc-4.8.2.orig/gcc/tree-ssa-forwprop.c gcc-4.8.2/gcc/tree-ssa-forwprop.c
--- gcc-4.8.2.orig/gcc/tree-ssa-forwprop.c 2013-02-25 16:31:31.000000000 +0100
+++ gcc-4.8.2/gcc/tree-ssa-forwprop.c 2014-03-22 19:37:04.797991879 +0100
@@ -688,6 +688,130 @@
recompute_tree_invariant_for_addr_expr (gimple_assign_rhs1 (stmt));
}
+ /* DEF_RHS contains the address of the 0th element in an array.
+ USE_STMT uses type of DEF_RHS to compute the address of an
+ arbitrary element within the array. The (variable) byte offset
+ of the element is contained in OFFSET.
+
+ We walk back through the use-def chains of OFFSET to verify that
+ it is indeed computing the offset of an element within the array
+ and extract the index corresponding to the given byte offset.
+
+ We then try to fold the entire address expression into a form
+ &array[index].
+
+ If we are successful, we replace the right hand side of USE_STMT
+ with the new address computation. */
+
+ static bool
+ forward_propagate_addr_into_variable_array_index (tree offset,
+ tree def_rhs,
+ gimple_stmt_iterator *use_stmt_gsi)
+ {
+ tree index, tunit;
+ gimple offset_def, use_stmt = gsi_stmt (*use_stmt_gsi);
+ tree new_rhs, tmp;
+
+ if (TREE_CODE (TREE_OPERAND (def_rhs, 0)) == ARRAY_REF)
+ tunit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (def_rhs)));
+ else if (TREE_CODE (TREE_TYPE (TREE_OPERAND (def_rhs, 0))) == ARRAY_TYPE)
+ tunit = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (TREE_TYPE (def_rhs))));
+ else
+ return false;
+ if (!host_integerp (tunit, 1))
+ return false;
+
+ /* Get the offset's defining statement. */
+ offset_def = SSA_NAME_DEF_STMT (offset);
+
+ /* Try to find an expression for a proper index. This is either a
+ multiplication expression by the element size or just the ssa name we came
+ along in case the element size is one. In that case, however, we do not
+ allow multiplications because they can be computing index to a higher
+ level dimension (PR 37861). */
+ if (integer_onep (tunit))
+ {
+ if (is_gimple_assign (offset_def)
+ && gimple_assign_rhs_code (offset_def) == MULT_EXPR)
+ return false;
+
+ index = offset;
+ }
+ else
+ {
+ /* The statement which defines OFFSET before type conversion
+ must be a simple GIMPLE_ASSIGN. */
+ if (!is_gimple_assign (offset_def))
+ return false;
+
+ /* The RHS of the statement which defines OFFSET must be a
+ multiplication of an object by the size of the array elements.
+ This implicitly verifies that the size of the array elements
+ is constant. */
+ if (gimple_assign_rhs_code (offset_def) == MULT_EXPR
+ && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
+ && tree_int_cst_equal (gimple_assign_rhs2 (offset_def), tunit))
+ {
+ /* The first operand to the MULT_EXPR is the desired index. */
+ index = gimple_assign_rhs1 (offset_def);
+ }
+ /* If we have idx * tunit + CST * tunit re-associate that. */
+ else if ((gimple_assign_rhs_code (offset_def) == PLUS_EXPR
+ || gimple_assign_rhs_code (offset_def) == MINUS_EXPR)
+ && TREE_CODE (gimple_assign_rhs1 (offset_def)) == SSA_NAME
+ && TREE_CODE (gimple_assign_rhs2 (offset_def)) == INTEGER_CST
+ && (tmp = div_if_zero_remainder (EXACT_DIV_EXPR,
+ gimple_assign_rhs2 (offset_def),
+ tunit)) != NULL_TREE)
+ {
+ gimple offset_def2 = SSA_NAME_DEF_STMT (gimple_assign_rhs1 (offset_def));
+ if (is_gimple_assign (offset_def2)
+ && gimple_assign_rhs_code (offset_def2) == MULT_EXPR
+ && TREE_CODE (gimple_assign_rhs2 (offset_def2)) == INTEGER_CST
+ && tree_int_cst_equal (gimple_assign_rhs2 (offset_def2), tunit))
+ {
+ index = fold_build2 (gimple_assign_rhs_code (offset_def),
+ TREE_TYPE (offset),
+ gimple_assign_rhs1 (offset_def2), tmp);
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+ }
+
+ /* Replace the pointer addition with array indexing. */
+ index = force_gimple_operand_gsi (use_stmt_gsi, index, true, NULL_TREE,
+ true, GSI_SAME_STMT);
+ if (TREE_CODE (TREE_OPERAND (def_rhs, 0)) == ARRAY_REF)
+ {
+ new_rhs = unshare_expr (def_rhs);
+ TREE_OPERAND (TREE_OPERAND (new_rhs, 0), 1) = index;
+ }
+ else
+ {
+ new_rhs = build4 (ARRAY_REF, TREE_TYPE (TREE_TYPE (TREE_TYPE (def_rhs))),
+ unshare_expr (TREE_OPERAND (def_rhs, 0)),
+ index, integer_zero_node, NULL_TREE);
+ new_rhs = build_fold_addr_expr (new_rhs);
+ if (!useless_type_conversion_p (TREE_TYPE (gimple_assign_lhs (use_stmt)),
+ TREE_TYPE (new_rhs)))
+ {
+ new_rhs = force_gimple_operand_gsi (use_stmt_gsi, new_rhs, true,
+ NULL_TREE, true, GSI_SAME_STMT);
+ new_rhs = fold_convert (TREE_TYPE (gimple_assign_lhs (use_stmt)),
+ new_rhs);
+ }
+ }
+ gimple_assign_set_rhs_from_tree (use_stmt_gsi, new_rhs);
+ fold_stmt (use_stmt_gsi);
+ tidy_after_forward_propagate_addr (gsi_stmt (*use_stmt_gsi));
+ return true;
+ }
+
+
+
/* NAME is a SSA_NAME representing DEF_RHS which is of the form
ADDR_EXPR <whatever>.
@@ -977,6 +1101,19 @@
tidy_after_forward_propagate_addr (use_stmt);
return true;
}
+ /* Try to optimize &x[0] p+ OFFSET where OFFSET is defined by
+ converting a multiplication of an index by the size of the
+ array elements, then the result is converted into the proper
+ type for the arithmetic. */
+ if (TREE_CODE (rhs2) == SSA_NAME
+ && (TREE_CODE (array_ref) != ARRAY_REF
+ || integer_zerop (TREE_OPERAND (array_ref, 1)))
+ && useless_type_conversion_p (TREE_TYPE (name), TREE_TYPE (def_rhs))
+ /* Avoid problems with IVopts creating PLUS_EXPRs with a
+ different type than their operands. */
+ && useless_type_conversion_p (TREE_TYPE (lhs), TREE_TYPE (def_rhs)))
+ return forward_propagate_addr_into_variable_array_index (rhs2, def_rhs,
+ use_stmt_gsi);
return false;
}
|