+ {
+ mark_type (from_type, FULL_ESCAPE);
+ cast = CT_TO_NON_INTER;
+ }
+
+ return cast;
+}
+
+
+/* Scan assignment statement S to see if there are any casts within it. */
+
+static unsigned int
+look_for_casts_stmt (gimple s)
+{
+ unsigned int cast = 0;
+
+ gcc_assert (is_gimple_assign (s));
+
+ if (gimple_assign_cast_p (s))
+ {
+ tree castfromvar = gimple_assign_rhs1 (s);
+ cast |= check_cast (TREE_TYPE (gimple_assign_lhs (s)), castfromvar);
+ }
+ else
+ {
+ size_t i;
+ for (i = 0; i < gimple_num_ops (s); i++)
+ cast |= look_for_casts (gimple_op (s, i));
+ }
+
+ if (!cast)
+ cast = CT_NO_CAST;
+
+ return cast;
+}
+
+
+typedef struct cast
+{
+ int type;
+ gimple stmt;
+} cast_t;
+
+/* This function is a callback for walk_use_def_chains function called
+ from is_array_access_through_pointer_and_index. */
+
+static bool
+is_cast_from_non_pointer (tree var, gimple def_stmt, void *data)
+{
+ if (!def_stmt || !var)
+ return false;
+
+ if (gimple_code (def_stmt) == GIMPLE_PHI)
+ return false;
+
+ if (SSA_NAME_IS_DEFAULT_DEF (var))
+ return false;
+
+ if (is_gimple_assign (def_stmt))
+ {
+ use_operand_p use_p;
+ ssa_op_iter iter;
+ unsigned int cast = look_for_casts_stmt (def_stmt);
+
+ /* Check that only one cast happened, and it's of non-pointer
+ type. */
+ if ((cast & CT_FROM_NON_P) == (CT_FROM_NON_P)
+ && (cast & ~(CT_FROM_NON_P)) == 0)
+ {
+ ((cast_t *)data)->stmt = def_stmt;
+ ((cast_t *)data)->type++;
+
+ FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_ALL_USES)
+ {
+ walk_use_def_chains (USE_FROM_PTR (use_p),
+ is_cast_from_non_pointer, data, false);
+ if (((cast_t*)data)->type == -1)
+ break;
+ }
+ }
+ /* Check that there is no cast, or cast is not harmful. */
+ else if ((cast & CT_NO_CAST) == (CT_NO_CAST)
+ || (cast & CT_DOWN) == (CT_DOWN)
+ || (cast & CT_UP) == (CT_UP)
+ || (cast & CT_USELESS) == (CT_USELESS)
+ || (cast & CT_FROM_MALLOC) == (CT_FROM_MALLOC))
+ {
+ FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_ALL_USES)
+ {
+ walk_use_def_chains (USE_FROM_PTR (use_p),
+ is_cast_from_non_pointer, data, false);
+ if (((cast_t*)data)->type == -1)
+ break;
+ }
+ }
+ /* The cast is harmful. */
+ else
+ ((cast_t *)data)->type = -1;
+ }
+
+ if (((cast_t*)data)->type == -1)
+ return true;
+
+ return false;
+}
+
+/* When array element a_p[i] is accessed through the pointer a_p
+ and index i, it's translated into the following sequence
+ in gimple:
+
+ i.1_5 = (unsigned int) i_1;
+ D.1605_6 = i.1_5 * 16;
+ D.1606_7 = (struct str_t *) D.1605_6;
+ a_p.2_8 = a_p;
+ D.1608_9 = D.1606_7 + a_p.2_8;
+
+ OP0 and OP1 are of the same pointer types and stand for
+ D.1606_7 and a_p.2_8 or vise versa.
+
+ This function checks that:
+
+ 1. one of OP0 and OP1 (D.1606_7) has passed only one cast from
+ non-pointer type (D.1606_7 = (struct str_t *) D.1605_6;).
+
+ 2. one of OP0 and OP1 which has passed the cast from
+ non-pointer type (D.1606_7), is actually generated by multiplication of
+ index by size of type to which both OP0 and OP1 point to
+ (in this case D.1605_6 = i.1_5 * 16; ).
+
+ 3. an address of def of the var to which was made cast (D.1605_6)
+ was not taken.(How can it happen?)
+
+ The following items are checked implicitly by the end of algorithm:
+
+ 4. one of OP0 and OP1 (a_p.2_8) have never been cast
+ (because if it was cast to pointer type, its type, that is also
+ the type of OP0 and OP1, will be marked as escaped during
+ analysis of casting stmt (when check_cast() is called
+ from scan_for_refs for this stmt)).
+
+ 5. defs of OP0 and OP1 are not passed into externally visible function
+ (because if they are passed then their type, that is also the type of OP0
+ and OP1, will be marked and escaped during check_call function called from
+ scan_for_refs with call stmt).
+
+ In total, 1-5 guaranty that it's an access to array by pointer and index.
+
+*/
+
+bool
+is_array_access_through_pointer_and_index (enum tree_code code, tree op0,
+ tree op1, tree *base, tree *offset,
+ gimple *offset_cast_stmt)
+{
+ tree before_cast;
+ gimple before_cast_def_stmt;
+ cast_t op0_cast, op1_cast;
+
+ *base = NULL;
+ *offset = NULL;
+ *offset_cast_stmt = NULL;
+
+ /* Check 1. */
+ if (code == POINTER_PLUS_EXPR)
+ {
+ tree op0type = TYPE_MAIN_VARIANT (TREE_TYPE (op0));
+ tree op1type = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
+
+ /* One of op0 and op1 is of pointer type and the other is numerical. */
+ if (POINTER_TYPE_P (op0type) && NUMERICAL_TYPE_CHECK (op1type))
+ {
+ *base = op0;
+ *offset = op1;
+ }
+ else if (POINTER_TYPE_P (op1type) && NUMERICAL_TYPE_CHECK (op0type))
+ {
+ *base = op1;
+ *offset = op0;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ /* Init data for walk_use_def_chains function. */
+ op0_cast.type = op1_cast.type = 0;
+ op0_cast.stmt = op1_cast.stmt = NULL;
+
+ visited_stmts = pointer_set_create ();
+ walk_use_def_chains (op0, is_cast_from_non_pointer,(void *)(&op0_cast),
+ false);
+ pointer_set_destroy (visited_stmts);
+
+ visited_stmts = pointer_set_create ();
+ walk_use_def_chains (op1, is_cast_from_non_pointer,(void *)(&op1_cast),
+ false);
+ pointer_set_destroy (visited_stmts);
+
+ if (op0_cast.type == 1 && op1_cast.type == 0)
+ {
+ *base = op1;
+ *offset = op0;
+ *offset_cast_stmt = op0_cast.stmt;
+ }
+ else if (op0_cast.type == 0 && op1_cast.type == 1)
+ {
+ *base = op0;
+ *offset = op1;
+ *offset_cast_stmt = op1_cast.stmt;
+ }
+ else
+ return false;
+ }
+
+ /* Check 2.
+ offset_cast_stmt is of the form:
+ D.1606_7 = (struct str_t *) D.1605_6; */
+
+ if (*offset_cast_stmt)
+ {
+ before_cast = SINGLE_SSA_TREE_OPERAND (*offset_cast_stmt, SSA_OP_USE);
+ if (!before_cast)
+ return false;
+
+ if (SSA_NAME_IS_DEFAULT_DEF (before_cast))
+ return false;
+
+ before_cast_def_stmt = SSA_NAME_DEF_STMT (before_cast);
+ if (!before_cast_def_stmt)
+ return false;
+ }
+ else
+ before_cast_def_stmt = SSA_NAME_DEF_STMT (*offset);
+
+ /* before_cast_def_stmt should be of the form:
+ D.1605_6 = i.1_5 * 16; */
+
+ if (is_gimple_assign (before_cast_def_stmt))
+ {
+ /* We expect temporary here. */
+ if (!is_gimple_reg (gimple_assign_lhs (before_cast_def_stmt)))
+ return false;
+
+ if (gimple_assign_rhs_code (before_cast_def_stmt) == MULT_EXPR)
+ {
+ tree arg0 = gimple_assign_rhs1 (before_cast_def_stmt);
+ tree arg1 = gimple_assign_rhs2 (before_cast_def_stmt);
+ tree unit_size =
+ TYPE_SIZE_UNIT (TREE_TYPE (TYPE_MAIN_VARIANT (TREE_TYPE (op0))));
+
+ if (!(CONSTANT_CLASS_P (arg0)
+ && simple_cst_equal (arg0, unit_size))
+ && !(CONSTANT_CLASS_P (arg1)
+ && simple_cst_equal (arg1, unit_size)))
+ return false;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+
+ /* Check 3.
+ check that address of D.1605_6 was not taken.
+ FIXME: if D.1605_6 is gimple reg than it cannot be addressable. */
+
+ return true;